Initial import of a UDF file system implementation for NetBSD.

The code supports read access to all media types that CD/DVD type drives
can recognize including DVD-RAM and BD- drives as well as harddisc partions
and vnd devices. UDF versions upto the latest 2.60 are to be supported
though due to lack of test media version 2.50 and 2.60 are not implemented
yet though easy to add. Both open and closed media are supported.

Write access is planned and in preparation. To facilitate this some hooks
are present in the code that are not strictly needed in a read-only
implementation but which allow writing to be added more easily.

Implemented and tested media types are CD-ROM, CD-R, CD-RW, CD-MRW,
DVD-ROM, DVD*R, DVD*RW, DVD+MRW but the same code can also read DVD-RAM,
HD-DVD and BluRay discs. Also vnd devices have been tested with several
sector sizes.

Discs created and written by UDFclient, Nero's InCD and Roxio's
DirectCD/Drag2Disc read fine.
This commit is contained in:
reinoud 2006-02-02 15:19:15 +00:00
parent 1b09e70fcd
commit cff5e7ad2c
14 changed files with 6836 additions and 0 deletions

7
sys/fs/udf/Makefile Normal file
View File

@ -0,0 +1,7 @@
# $NetBSD: Makefile,v 1.1 2006/02/02 15:19:15 reinoud Exp $
INCSDIR= /usr/include/fs/udf
INCS= ecma167-udf.h udf_mount.h
.include <bsd.kinc.mk>

798
sys/fs/udf/ecma167-udf.h Normal file
View File

@ -0,0 +1,798 @@
/* $NetBSD: ecma167-udf.h,v 1.1 2006/02/02 15:19:15 reinoud Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006 Reinoud Zandijk <reinoud@netbsd.org>
* Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* Extended and adapted for UDFv2.50+ bij Reinoud Zandijk based on the
* origional by Scott Long.
*
* 20030508 Made some small typo and explainatory comments
* 20030510 Added UDF 2.01 structures
* 20030519 Added/correct comments on multi-partitioned logical volume space
* 20050616 Added pseudo overwrite
* 20050624 Added the missing extended attribute types and `magic values'.
* 20051106 Reworked some implementation use parts
*
*/
#ifndef _ECMA167_UDF_H_
#define _ECMA167_UDF_H_
/*
* in case of an older gcc versions, define the __packed as explicit
* attribute
*/
/*
* You may specify the `aligned' and `transparent_union' attributes either in
* a `typedef' declaration or just past the closing curly brace of a complete
* enum, struct or union type _definition_ and the `packed' attribute only
* past the closing brace of a definition. You may also specify attributes
* between the enum, struct or union tag and the name of the type rather than
* after the closing brace.
*/
#ifndef __packed
#define __packed __attribute__((packed))
#endif
/* ecma167-udf.h */
/* Volume recognition sequence ECMA 167 rev. 3 16.1 */
struct vrs_desc {
uint8_t struct_type;
uint8_t identifier[5];
uint8_t version;
uint8_t data[2041];
} __packed;
#define VRS_NSR02 "NSR02"
#define VRS_NSR03 "NSR03"
#define VRS_BEA01 "BEA01"
#define VRS_TEA01 "TEA01"
#define VRS_CD001 "CD001"
#define VRS_CDW02 "CDW02"
/* Structure/definitions/constants a la ECMA 167 rev. 3 */
#define MAX_TAGID_VOLUMES 9
/* Tag identifiers */
enum {
TAGID_SPARING_TABLE = 0,
TAGID_PRI_VOL = 1,
TAGID_ANCHOR = 2,
TAGID_VOL = 3,
TAGID_IMP_VOL = 4,
TAGID_PARTITION = 5,
TAGID_LOGVOL = 6,
TAGID_UNALLOC_SPACE = 7,
TAGID_TERM = 8,
TAGID_LOGVOL_INTEGRITY= 9,
TAGID_FSD = 256,
TAGID_FID = 257,
TAGID_ALLOCEXTENT = 258,
TAGID_INDIRECT_ENTRY = 259,
TAGID_ICB_TERM = 260,
TAGID_FENTRY = 261,
TAGID_EXTATTR_HDR = 262,
TAGID_UNALL_SP_ENTRY = 263,
TAGID_SPACE_BITMAP = 264,
TAGID_PART_INTEGRETY = 265,
TAGID_EXTFENTRY = 266,
TAGID_MAX = 266
};
enum {
UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT = 1,
UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT = 2
};
enum {
UDF_ACCESSTYPE_NOT_SPECIFIED = 0, /* unknown */
UDF_ACCESSTYPE_PSEUDO_OVERWITE = 0, /* Pseudo overwritable, f.e. BD-R's LOW */
UDF_ACCESSTYPE_READ_ONLY = 1, /* really only readable */
UDF_ACCESSTYPE_WRITE_ONCE = 2, /* write once and you're done */
UDF_ACCESSTYPE_REWRITEABLE = 3, /* may need extra work to rewrite */
UDF_ACCESSTYPE_OVERWRITABLE = 4 /* no limits on rewriting; harddisc f.e.*/
};
/* Descriptor tag [3/7.2] */
struct desc_tag {
uint16_t id;
uint16_t descriptor_ver;
uint8_t cksum;
uint8_t reserved;
uint16_t serial_num;
uint16_t desc_crc;
uint16_t desc_crc_len;
uint32_t tag_loc;
} __packed;
#define UDF_DESC_TAG_LENGTH 16
/* Recorded Address [4/7.1] */
struct lb_addr { /* within partition space */
uint32_t lb_num;
uint16_t part_num;
} __packed;
/* Extent Descriptor [3/7.1] */
struct extent_ad {
uint32_t len;
uint32_t loc;
} __packed;
/* Short Allocation Descriptor [4/14.14.1] */
struct short_ad {
uint32_t len;
uint32_t lb_num;
} __packed;
/* Long Allocation Descriptor [4/14.14.2] */
struct UDF_ADImp_use {
uint16_t flags;
uint32_t unique_id;
} __packed;
#define UDF_ADIMP_FLAGS_EXTENT_ERASED 1
struct long_ad {
uint32_t len;
struct lb_addr loc; /* within a logical volume mapped partition space !! */
union {
uint8_t bytes[6];
struct UDF_ADImp_use im_used;
} __packed impl;
} __packed;
/* Extended Allocation Descriptor [4/14.14.3] ; identifies an extent of allocation descriptors ; also in UDF ? */
struct ext_ad {
uint32_t ex_len;
uint32_t rec_len;
uint32_t inf_len;
struct lb_addr ex_loc;
uint8_t reserved[2];
} __packed;
/* ICB : Information Control Block; positioning */
union icb {
struct short_ad s_ad;
struct long_ad l_ad;
struct ext_ad e_ad;
} __packed;
/* short/long/ext extent have flags encoded in length */
#define UDF_EXT_ALLOCATED (0<<30)
#define UDF_EXT_FREED (1<<30)
#define UDF_EXT_ALLOCATED_BUT_NOT_USED (1<<30)
#define UDF_EXT_FREE (2<<30)
#define UDF_EXT_REDIRECT (3<<30)
#define UDF_EXT_FLAGS(len) ((len) & (3<<30))
#define UDF_EXT_LEN(len) ((len) & ((1<<30)-1))
/* Character set spec [1/7.2.1] */
struct charspec {
uint8_t type;
uint8_t inf[63];
} __packed;
/* Timestamp [1/7.3] */
struct timestamp {
uint16_t type_tz;
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t centisec;
uint8_t hund_usec;
uint8_t usec;
} __packed;
/* Entity Identifier [1/7.4] */
#define UDF_REGID_ID_SIZE 23
struct regid {
uint8_t flags;
uint8_t id[UDF_REGID_ID_SIZE];
uint8_t id_suffix[8];
} __packed;
/* ICB Tag [4/14.6] */
struct icb_tag {
uint32_t prev_num_dirs;
uint16_t strat_type;
uint8_t strat_param[2];
uint16_t max_num_entries;
uint8_t reserved;
uint8_t file_type;
struct lb_addr parent_icb;
uint16_t flags;
} __packed;
#define UDF_ICB_TAG_FLAGS_ALLOC_MASK 0x03
#define UDF_ICB_SHORT_ALLOC 0x00
#define UDF_ICB_LONG_ALLOC 0x01
#define UDF_ICB_EXT_ALLOC 0x02
#define UDF_ICB_INTERN_ALLOC 0x03
#define UDF_ICB_TAG_FLAGS_DIRORDERED (1<< 3)
#define UDF_ICB_TAG_FLAGS_NONRELOC (1<< 4)
#define UDF_ICB_TAG_FLAGS_CONTIGUES (1<< 9)
#define UDF_ICB_TAG_FLAGS_MULTIPLEVERS (1<<12)
#define UDF_ICB_TAG_FLAGS_SETUID (1<< 6)
#define UDF_ICB_TAG_FLAGS_SETGID (1<< 7)
#define UDF_ICB_TAG_FLAGS_STICKY (1<< 8)
#define UDF_ICB_FILETYPE_UNKNOWN 0
#define UDF_ICB_FILETYPE_UNALLOCSPACE 1
#define UDF_ICB_FILETYPE_PARTINTEGRITY 2
#define UDF_ICB_FILETYPE_INDIRECTENTRY 3
#define UDF_ICB_FILETYPE_DIRECTORY 4
#define UDF_ICB_FILETYPE_RANDOMACCESS 5
#define UDF_ICB_FILETYPE_BLOCKDEVICE 6
#define UDF_ICB_FILETYPE_CHARDEVICE 7
#define UDF_ICB_FILETYPE_EXTATTRREC 8
#define UDF_ICB_FILETYPE_FIFO 9
#define UDF_ICB_FILETYPE_SOCKET 10
#define UDF_ICB_FILETYPE_TERM 11
#define UDF_ICB_FILETYPE_SYMLINK 12
#define UDF_ICB_FILETYPE_STREAMDIR 13
#define UDF_ICB_FILETYPE_VAT 248
#define UDF_ICB_FILETYPE_META_MAIN 250
#define UDF_ICB_FILETYPE_META_MIRROR 251
/* Anchor Volume Descriptor Pointer [3/10.2] */
struct anchor_vdp {
struct desc_tag tag;
struct extent_ad main_vds_ex; /* to main volume descriptor set ; 16 sectors min */
struct extent_ad reserve_vds_ex; /* copy of main volume descriptor set ; 16 sectors min */
} __packed;
/* Volume Descriptor Pointer [3/10.3] */
struct vol_desc_ptr {
struct desc_tag tag; /* use for extending the volume descriptor space */
uint32_t vds_number;
struct extent_ad next_vds_ex; /* points to the next block for volume descriptor space */
} __packed;
/* Primary Volume Descriptor [3/10.1] */
struct pri_vol_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevail */
uint32_t pvd_num; /* assigned by author; 0 is special as in it may only occure once */
char vol_id[32]; /* KEY ; main identifier of this disc */
uint16_t vds_num; /* volume descriptor number; i.e. what volume number is it */
uint16_t max_vol_seq; /* maximum volume descriptor number known */
uint16_t ichg_lvl;
uint16_t max_ichg_lvl;
uint32_t charset_list;
uint32_t max_charset_list;
char volset_id[128]; /* KEY ; if part of a multi-disc set or a band of volumes */
struct charspec desc_charset; /* KEY according to ECMA 167 */
struct charspec explanatory_charset;
struct extent_ad vol_abstract;
struct extent_ad vol_copyright;
struct regid app_id;
struct timestamp time;
struct regid imp_id;
uint8_t imp_use[64];
uint32_t prev_vds_loc; /* location of predecessor _lov ? */
uint16_t flags; /* bit 0 : if set indicates volume set name is meaningfull */
uint8_t reserved[22];
} __packed;
/* UDF specific implementation use part of the implementation use volume descriptor */
struct udf_lv_info {
struct charspec lvi_charset;
char logvol_id[128];
char lvinfo1[36];
char lvinfo2[36];
char lvinfo3[36];
struct regid impl_id;
uint8_t impl_use[128];
} __packed;
/* Implementation use Volume Descriptor */
struct impvol_desc {
struct desc_tag tag;
uint32_t seq_num;
struct regid impl_id;
union {
struct udf_lv_info lv_info;
char impl_use[460];
} __packed _impl_use;
} __packed;
/* Logical Volume Descriptor [3/10.6] */
struct logvol_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevail */
struct charspec desc_charset; /* KEY */
char logvol_id[128]; /* KEY */
uint32_t lb_size;
struct regid domain_id;
union {
struct long_ad fsd_loc; /* to fileset descriptor SEQUENCE */
uint8_t logvol_content_use[16];
} __packed _lvd_use;
uint32_t mt_l; /* Partition map length */
uint32_t n_pm; /* Number of partition maps */
struct regid imp_id;
uint8_t imp_use[128];
struct extent_ad integrity_seq_loc;
uint8_t maps[1];
} __packed;
#define lv_fsd_loc _lvd_use.fsd_loc
#define UDF_INTEGRITY_OPEN 0
#define UDF_INTEGRITY_CLOSED 1
#define UDF_PMAP_SIZE 64
/* Type 1 Partition Map [3/10.7.2] */
struct part_map_1 {
uint8_t type;
uint8_t len;
uint16_t vol_seq_num;
uint16_t part_num;
} __packed;
/* Type 2 Partition Map [3/10.7.3] */
struct part_map_2 {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid part_id;
uint16_t vol_seq_num;
uint16_t part_num;
uint8_t reserved2[24];
} __packed;
/* Virtual Partition Map [UDF 2.01/2.2.8] */
struct part_map_virt {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid id;
uint16_t vol_seq_num;
uint16_t part_num;
uint8_t reserved1[24];
} __packed;
/* Sparable Partition Map [UDF 2.01/2.2.9] */
struct part_map_spare {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid id;
uint16_t vol_seq_num;
uint16_t part_num;
uint16_t packet_len;
uint8_t n_st; /* Number of redundant sparing tables range 1-4 */
uint8_t reserved1;
uint32_t st_size; /* size of EACH sparing table */
uint32_t st_loc[1]; /* locations of sparing tables */
} __packed;
/* Metadata Partition Map [UDF 2.50/2.2.10] */
struct part_map_meta {
uint8_t type;
uint8_t len;
uint8_t reserved[2];
struct regid id;
uint16_t vol_seq_num;
uint16_t part_num;
uint32_t meta_file_lbn; /* logical block number for file entry within part_num */
uint32_t meta_mirror_file_lbn;
uint32_t meta_bitmap_file_lbn;
uint32_t alloc_unit_size; /* allocation unit size in blocks */
uint16_t alignment_unit_size; /* alignment nessisary in blocks */
uint8_t flags;
uint8_t reserved1[5];
} __packed;
#define METADATA_DUPLICATED 1
union udf_pmap {
uint8_t data[UDF_PMAP_SIZE];
struct part_map_1 pm1;
struct part_map_2 pm2;
struct part_map_virt pmv;
struct part_map_spare pms;
struct part_map_meta pmm;
} __packed;
/* Sparing Map Entry [UDF 2.01/2.2.11] */
struct spare_map_entry {
uint32_t org; /* partion relative address */
uint32_t map; /* absolute disc address (!) can be in partion, but doesn't have to be */
} __packed;
/* Sparing Table [UDF 2.01/2.2.11] */
struct udf_sparing_table {
struct desc_tag tag;
struct regid id;
uint16_t rt_l; /* Relocation Table len */
uint8_t reserved[2];
uint32_t seq_num;
struct spare_map_entry entries[1];
} __packed;
/* VAT table [UDF 2.0.1/2.2.10] */
struct udf_vat {
uint16_t header_len;
uint16_t impl_use_len;
char logvol_id[128]; /* newer version of the LVD one */
uint32_t prev_vat;
uint32_t num_files;
uint32_t num_directories;
uint16_t min_udf_readver;
uint16_t min_udf_writever;
uint16_t max_udf_writever;
uint16_t reserved;
uint8_t data[1]; /* impl.use followed by VAT entries (uint32_t) */
} __packed;
/* Space bitmap descriptor as found in the partition header descriptor */
struct space_bitmap_desc {
struct desc_tag tag; /* TagId 264 */
uint32_t num_bits; /* number of bits */
uint32_t num_bytes; /* bytes that contain it */
uint8_t data[1];
} __packed;
/* Unalloc space entry as found in the partition header descriptor */
struct space_entry_desc {
struct desc_tag tag; /* TagId 263 */
struct icb_tag icbtag; /* type 1 */
uint32_t l_ad; /* in bytes */
uint8_t entry[1];
} __packed;
/* Partition header descriptor; in the contents_use of part_desc */
struct part_hdr_desc {
struct short_ad unalloc_space_table;
struct short_ad unalloc_space_bitmap;
struct short_ad part_integrety_table; /* has to be ZERO for UDF */
struct short_ad freed_space_table;
struct short_ad freed_space_bitmap;
uint8_t reserved[88];
} __packed;
/* Partition Descriptor [3/10.5] */
struct part_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevailing */
uint16_t flags; /* bit 0 : if set the space is allocated */
uint16_t part_num; /* KEY */
struct regid contents;
union {
struct part_hdr_desc part_hdr;
uint8_t contents_use[128];
} _impl_use;
uint32_t access_type; /* R/W, WORM etc. */
uint32_t start_loc; /* start of partion with given length */
uint32_t part_len;
struct regid imp_id;
uint8_t imp_use[128];
uint8_t reserved[156];
} __packed;
#define pd_part_hdr _impl_use.part_hdr
#define UDF_PART_FLAG_ALLOCATED 1
/* Unallocated Space Descriptor (UDF 2.01/2.2.5) */
struct unalloc_sp_desc {
struct desc_tag tag;
uint32_t seq_num; /* MAX prevailing */
uint32_t alloc_desc_num;
struct extent_ad alloc_desc[1];
} __packed;
/* Logical Volume Integrity Descriptor [3/30.10] */
struct logvolhdr {
uint64_t next_unique_id;
/* rest reserved */
} __packed;
struct udf_logvol_info {
struct regid impl_id;
uint32_t num_files;
uint32_t num_directories;
uint16_t min_udf_readver;
uint16_t min_udf_writever;
uint16_t max_udf_writever;
} __packed;
struct logvol_int_desc {
struct desc_tag tag;
struct timestamp time;
uint32_t integrity_type;
struct extent_ad next_extent;
union {
struct logvolhdr logvolhdr;
int8_t reserved[32];
} __packed _impl_use;
uint32_t num_part;
uint32_t l_iu;
uint32_t tables[1]; /* Freespace table, Sizetable, Implementation use */
} __packed;
#define lvint_next_unique_id _impl_use.logvolhdr.next_unique_id
/* File Set Descriptor [4/14.1] */
struct fileset_desc {
struct desc_tag tag;
struct timestamp time;
uint16_t ichg_lvl;
uint16_t max_ichg_lvl;
uint32_t charset_list;
uint32_t max_charset_list;
uint32_t fileset_num; /* key! */
uint32_t fileset_desc_num;
struct charspec logvol_id_charset;
char logvol_id[128]; /* for recovery */
struct charspec fileset_charset;
char fileset_id[32]; /* Mountpoint !! */
char copyright_file_id[32];
char abstract_file_id[32];
struct long_ad rootdir_icb; /* to rootdir; icb->virtual ? */
struct regid domain_id;
struct long_ad next_ex; /* to the next fileset_desc extent */
struct long_ad streamdir_icb; /* streamdir; needed? */
uint8_t reserved[32];
} __packed;
/* File Identifier Descriptor [4/14.4] */
struct fileid_desc {
struct desc_tag tag;
uint16_t file_version_num;
uint8_t file_char;
uint8_t l_fi; /* Length of file identifier area */
struct long_ad icb;
uint16_t l_iu; /* Length of implementation use area */
uint8_t data[1];
} __packed;
#define UDF_FID_SIZE 38
#define UDF_FILE_CHAR_VIS (1 << 0) /* Invisible */
#define UDF_FILE_CHAR_DIR (1 << 1) /* Directory */
#define UDF_FILE_CHAR_DEL (1 << 2) /* Deleted */
#define UDF_FILE_CHAR_PAR (1 << 3) /* Parent Directory */
#define UDF_FILE_CHAR_META (1 << 4) /* Stream metadata */
/* Extended attributes [4/14.10.1] */
struct extattrhdr_desc {
struct desc_tag tag;
uint32_t impl_attr_loc; /* offsets within this descriptor */
uint32_t appl_attr_loc; /* ditto */
} __packed;
#define UDF_IMPL_ATTR_LOC_NOT_PRESENT 0xffffffff
#define UDF_APPL_ATTR_LOC_NOT_PRESENT 0xffffffff
/* Extended attribute entry [4/48.10.2] */
struct extattr_entry {
uint32_t type;
uint8_t subtype;
uint8_t reserved[3];
uint32_t a_l;
} __packed;
/* Extended attribute entry; type 2048 [4/48.10.8] */
struct impl_extattr_entry {
struct extattr_entry hdr;
uint32_t iu_l;
struct regid imp_id;
uint16_t cksum; /* UDF: of header */
uint8_t data[1];
} __packed;
/* Extended attribute entry; type 65 536 [4/48.10.9] */
struct appl_extattr_entry {
struct extattr_entry hdr;
uint32_t au_l;
struct regid appl_id;
uint8_t data[1];
} __packed;
/* File Times attribute entry; type 5 or type 6 [4/48.10.5], [4/48.10.6] */
struct filetimes_extattr_entry {
struct extattr_entry hdr;
uint32_t d_l; /* length of times[] data following */
uint32_t existence; /* bitmask */
struct timestamp times[1]; /* in order of assending bits */
} __packed;
/* Device Specification Extended Attribute [4/4.10.7] */
struct device_extattr_entry {
struct extattr_entry hdr;
uint32_t iu_l; /* length of implementation use */
uint32_t major;
uint32_t minor;
uint8_t data[1]; /* UDF: if nonzero length, contain developer ID regid */
} __packed;
/* File Entry [4/14.9] */
struct file_entry {
struct desc_tag tag;
struct icb_tag icbtag;
uint32_t uid;
uint32_t gid;
uint32_t perm;
uint16_t link_cnt;
uint8_t rec_format;
uint8_t rec_disp_attr;
uint32_t rec_len;
uint64_t inf_len;
uint64_t logblks_rec;
struct timestamp atime;
struct timestamp mtime;
struct timestamp attrtime;
uint32_t ckpoint;
struct long_ad ex_attr_icb;
struct regid imp_id;
uint64_t unique_id;
uint32_t l_ea; /* Length of extended attribute area */
uint32_t l_ad; /* Length of allocation descriptors */
uint8_t data[1];
} __packed;
#define UDF_FENTRY_SIZE 176
#define UDF_FENTRY_PERM_USER_MASK 0x07
#define UDF_FENTRY_PERM_GRP_MASK 0xE0
#define UDF_FENTRY_PERM_OWNER_MASK 0x1C00
/* Extended File Entry [4/48.17] */
struct extfile_entry {
struct desc_tag tag;
struct icb_tag icbtag;
uint32_t uid;
uint32_t gid;
uint32_t perm;
uint16_t link_cnt;
uint8_t rec_format;
uint8_t rec_disp_attr;
uint32_t rec_len;
uint64_t inf_len;
uint64_t obj_size;
uint64_t logblks_rec;
struct timestamp atime;
struct timestamp mtime;
struct timestamp ctime;
struct timestamp attrtime;
uint32_t ckpoint;
uint32_t reserved1;
struct long_ad ex_attr_icb;
struct long_ad streamdir_icb;
struct regid imp_id;
uint64_t unique_id;
uint32_t l_ea; /* Length of extended attribute area */
uint32_t l_ad; /* Length of allocation descriptors */
uint8_t data[1];
} __packed;
/* Indirect entry [ecma 48.7] */
struct indirect_entry {
struct desc_tag tag;
struct icb_tag icbtag;
struct long_ad indirect_icb;
} __packed;
/* Allocation extent descritor [ecma 48.5] */
struct alloc_ext_entry {
struct desc_tag tag;
uint32_t prev_entry;
uint32_t l_ad;
uint8_t data[1];
} __packed;
union dscrptr {
struct desc_tag tag;
struct anchor_vdp avdp;
struct vol_desc_ptr vdp;
struct pri_vol_desc pvd;
struct logvol_desc lvd;
struct unalloc_sp_desc usd;
struct logvol_int_desc lvid;
struct impvol_desc ivd;
struct part_desc pd;
struct fileset_desc fsd;
struct fileid_desc fid;
struct file_entry fe;
struct extfile_entry efe;
struct extattrhdr_desc eahd;
struct indirect_entry inde;
struct alloc_ext_entry aee;
struct udf_sparing_table spt;
struct space_bitmap_desc sbd;
struct space_entry_desc sed;
} __packed;
/* Useful defines */
#define GETICB(ad_type, fentry, offset) \
(struct ad_type *)&fentry->data[offset]
#define GETICBLEN(ad_type, icb) ((struct ad_type *)(icb))->len
#endif /* !_ECMA167_UDF_H_ */

9
sys/fs/udf/files.udf Normal file
View File

@ -0,0 +1,9 @@
# $NetBSD: files.udf,v 1.1 2006/02/02 15:19:15 reinoud Exp $
deffs fs_udf.h UDF
file fs/udf/udf_osta.c udf
file fs/udf/udf_vfsops.c udf
file fs/udf/udf_vnops.c udf
file fs/udf/udf_subr.c udf

253
sys/fs/udf/udf.h Normal file
View File

@ -0,0 +1,253 @@
/* $NetBSD $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/queue.h>
#include <sys/uio.h>
#include "udf_osta.h"
#include "ecma167-udf.h"
#include <sys/cdio.h>
#include <miscfs/genfs/genfs_node.h>
#ifndef _UDF_H_
#define _UDF_H_
/* TODO make `udf_verbose' set by sysctl */
/* debug section */
extern int udf_verbose;
/* initial value of udf_verbose */
#define UDF_DEBUGGING 0x000
/* debug categories */
#define UDF_DEBUG_VOLUMES 0x001
#define UDF_DEBUG_LOCKING 0x002
#define UDF_DEBUG_NODE 0x004
#define UDF_DEBUG_LOOKUP 0x008
#define UDF_DEBUG_READDIR 0x010
#define UDF_DEBUG_FIDS 0x020
#define UDF_DEBUG_DESCRIPTOR 0x040
#define UDF_DEBUG_TRANSLATE 0x080
#define UDF_DEBUG_STRATEGY 0x100
#define UDF_DEBUG_READ 0x200
#define UDF_DEBUG_CALL 0x400
#define UDF_DEBUG_NOTIMPL UDF_DEBUG_CALL
#ifdef DEBUG
#define DPRINTF(name, arg) { \
if (udf_verbose & UDF_DEBUG_##name) {\
printf arg;\
};\
}
#define DPRINTFIF(name, cond, arg) { \
if (udf_verbose & UDF_DEBUG_##name) { \
if (cond) printf arg;\
};\
}
#else
#define DPRINTF(name, arg) {}
#define DPRINTFIF(name, cond, arg) {}
#endif
/* constants to identify what kind of identifier we are dealing with */
#define UDF_REGID_DOMAIN 1
#define UDF_REGID_UDF 2
#define UDF_REGID_IMPLEMENTATION 3
#define UDF_REGID_APPLICATION 4
#define UDF_REGID_NAME 99
/* DON'T change these: they identify 13thmonkey's UDF implementation */
#define APP_NAME "*NetBSD UDF"
#define APP_VERSION_MAIN 1
#define APP_VERSION_SUB 0
#define IMPL_NAME "*13thMonkey.org"
/* Configuration values */
#define UDF_INODE_HASHBITS 10
#define UDF_INODE_HASHSIZE (1<<UDF_INODE_HASHBITS)
#define UDF_INODE_HASHMASK (UDF_INODE_HASHSIZE - 1)
/* structure space */
#define UDF_ANCHORS 4 /* 256, 512, N-256, N */
#define UDF_PARTITIONS 4 /* overkill */
#define UDF_PMAPS 4 /* overkill */
/* constants */
#define UDF_MAX_NAMELEN 255 /* as per SPEC */
#define UDF_TRANS_ZERO ((uint64_t) -1)
#define UDF_TRANS_UNMAPPED ((uint64_t) -2)
#define UDF_TRANS_INTERN ((uint64_t) -3)
#define UDF_MAX_SECTOR ((uint64_t) -10) /* high water mark */
/* malloc pools */
MALLOC_DECLARE(M_UDFMNT);
MALLOC_DECLARE(M_UDFVOLD);
MALLOC_DECLARE(M_UDFTEMP);
struct pool udf_node_pool;
struct udf_node;
/* pre cleanup */
struct udf_mount {
struct mount *vfs_mountp;
struct vnode *devvp;
struct mmc_discinfo discinfo;
struct udf_args mount_args;
/* read in structures */
struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */
struct pri_vol_desc *primary_vol; /* identification */
struct logvol_desc *logical_vol; /* main mapping v->p */
struct unalloc_sp_desc *unallocated; /* free UDF space */
struct impvol_desc *implementation; /* likely reduntant */
struct logvol_int_desc *logvol_integrity; /* current integrity */
struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */
/* derived; points *into* other structures */
struct udf_logvol_info *logvol_info; /* integrity descr. */
/* fileset and root directories */
struct fileset_desc *fileset_desc; /* normally one */
/* logical to physical translations */
int vtop[UDF_PMAPS+1]; /* vpartnr trans */
int vtop_tp[UDF_PMAPS+1]; /* type of trans */
uint32_t possible_vat_location; /* predicted */
uint32_t vat_table_alloc_length;
uint32_t vat_entries;
uint32_t vat_offset; /* offset in table */
uint8_t *vat_table; /* read in data */
uint32_t sparable_packet_len;
struct udf_sparing_table*sparing_table;
struct udf_node *metafile;
struct udf_node *metabitmapfile;
struct udf_node *metacopyfile;
struct udf_node *metabitmapcopyfile;
/* disc allocation */
int data_alloc, meta_alloc; /* allocation scheme */
struct mmc_trackinfo datatrack;
struct mmc_trackinfo metadatatrack;
/* TODO free space and usage per partition */
/* ... [UDF_PARTITIONS]; */
/* hash table to lookup ino_t -> udf_node */
LIST_HEAD(, udf_node) udf_nodes[UDF_INODE_HASHSIZE];
/* allocation pool for udf_node's descriptors */
struct pool desc_pool;
/* locks */
struct simplelock ihash_slock;
struct lock get_node_lock;
/* lists */
STAILQ_HEAD(, udf_node) dirty_nodes;
STAILQ_HEAD(udfmntpts, udf_mount) all_udf_mntpnts;
};
#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */
/* virtual to physical mapping types */
#define UDF_VTOP_TYPE_RAW 0
#define UDF_VTOP_TYPE_UNKNOWN 0
#define UDF_VTOP_TYPE_PHYS 1
#define UDF_VTOP_TYPE_VIRT 2
#define UDF_VTOP_TYPE_SPARABLE 3
#define UDF_VTOP_TYPE_META 4
/* allocation strategies */
#define UDF_ALLOC_SPACEMAP 1 /* spacemaps */
#define UDF_ALLOC_SEQUENTIAL 2 /* linear on NWA */
#define UDF_ALLOC_VAT 3 /* VAT handling */
#define UDF_ALLOC_METABITMAP 4 /* metadata bitmap */
#define UDF_ALLOC_METASEQUENTIAL 5 /* in chunks seq., nodes not seq */
#define UDF_ALLOC_RELAXEDSEQUENTIAL 6 /* only nodes not seq. */
/* readdir cookies */
#define UDF_DIRCOOKIE_DOT 1
struct udf_node {
struct genfs_node i_gnode; /* has to be first */
struct vnode *vnode; /* vnode associated */
struct udf_mount *ump;
/* one of `fe' or `efe' can be set, not both (UDF file entry dscr.) */
struct file_entry *fe;
struct extfile_entry *efe;
/* location found and recording location & hints */
struct long_ad loc; /* FID/hash loc. */
struct long_ad next_loc; /* strat 4096 loc */
int needs_indirect; /* has missing indr. */
/* TODO support for allocation extents? */
/* device number from extended attributes = makedev(min,maj) */
dev_t rdev;
/* misc */
struct lockf *lockf; /* lock list */
/* possibly not needed */
long refcnt;
int dirty;
int hold;
struct udf_node *extattr;
struct udf_node *streamdir;
LIST_ENTRY(udf_node) hashchain; /* all udf nodes */
STAILQ_ENTRY(udf_node) dirty_nodes; /* dirty udf nodes */
};
#endif /* !_UDF_H_ */

97
sys/fs/udf/udf_bswap.h Normal file
View File

@ -0,0 +1,97 @@
/* $NetBSD: udf_bswap.h,v 1.1 2006/02/02 15:19:15 reinoud Exp $ */
/*
* Copyright (c) 1998 Manuel Bouyer.
*
* 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* adapted for UDF by Reinoud Zandijk <reinoud@netbsd.org>
*
*/
#ifndef _UDF_BSWAP_H_
#define _UDF_BSWAP_H_
#if HAVE_ENDIAN_H
#include <endian.h>
#else
#if HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#else
#if HAVE_MACHINE_ENDIAN_H
#include <machine/endian.h>
#endif
#endif
#endif
/* rest only relevant for big endian machines */
#if (BYTE_ORDER == BIG_ENDIAN)
#include <machine/bswap.h>
#include <sys/bswap.h>
/* inlines for access to swapped data */
static __inline u_int16_t udf_rw16 __P((u_int16_t));
static __inline u_int32_t udf_rw32 __P((u_int32_t));
static __inline u_int64_t udf_rw64 __P((u_int64_t));
static __inline u_int16_t
udf_rw16(a)
u_int16_t a;
{
return bswap16(a);
}
static __inline u_int32_t
udf_rw32(a)
u_int32_t a;
{
return bswap32(a);
}
static __inline u_int64_t
udf_rw64(a)
u_int64_t a;
{
return bswap64(a);
}
#else
#define udf_rw16(a) ((uint16_t)(a))
#define udf_rw32(a) ((uint32_t)(a))
#define udf_rw64(a) ((uint64_t)(a))
#endif
#endif /* !_UDF_BSWAP_H_ */

70
sys/fs/udf/udf_mount.h Normal file
View File

@ -0,0 +1,70 @@
/* $NetBSD $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _UDF_MOUNT_H_
#define _UDF_MOUNT_H_
/*
* Arguments to mount UDF filingsystem.
*/
#define UDFMNT_VERSION 1
struct udf_args {
uint32_t version; /* version of this structure */
char *fspec; /* mount specifier */
int32_t sessionnr; /* session specifier, rel of abs */
uint32_t udfmflags; /* mount options */
int32_t gmtoff; /* offset from UTC in seconds */
uid_t anon_uid; /* mapping of anonymous files uid */
gid_t anon_gid; /* mapping of anonymous files gid */
uid_t nobody_uid; /* nobody:nobody will map to -1:-1 */
gid_t nobody_gid; /* nobody:nobody will map to -1:-1 */
uint32_t sector_size; /* for mounting dumps/files */
/* extendable */
uint8_t reserved[32];
};
/* udf mount options */
#define UDFMNT_CLOSESESSION 0x00000001 /* close session on dismount */
#define UDFMNT_BITS "\20\1CLOSESESSION"
#endif /* !_UDF_MOUNT_H_ */

488
sys/fs/udf/udf_osta.c Normal file
View File

@ -0,0 +1,488 @@
/* $NetBSD: udf_osta.c,v 1.1 2006/02/02 15:19:16 reinoud Exp $ */
/*
* 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.
*
*/
#include "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.
*/
/***********************************************************************
* 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.
*/
/* #include <stdio.h> */
static int UnicodeIsPrint(unicode_t ch) {
return (ch >=' ') && (ch < 127);
};
int UnicodeLength(unicode_t *string) {
int length;
length = 0;
while (*string++) length++;
return length;
};
static int isprint(unsigned char c) {
return (c >= ' ') && (c != 127);
};
/***********************************************************************
* 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*/ /* NEEDS_ISPRINT */

41
sys/fs/udf/udf_osta.h Normal file
View File

@ -0,0 +1,41 @@
/* $NetBSD: udf_osta.h,v 1.1 2006/02/02 15:19:16 reinoud Exp $ */
/*
* Prototypes for the OSTA functions
*/
#ifndef _OSTA_H_
#define _OSTA_H_
#include <sys/types.h>
#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 uint16_t unicode_t;
typedef uint8_t 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);
int UnicodeLength(unicode_t *string);
#endif /* _OSTA_H_ */

2834
sys/fs/udf/udf_subr.c Normal file

File diff suppressed because it is too large Load Diff

117
sys/fs/udf/udf_subr.h Normal file
View File

@ -0,0 +1,117 @@
/* $NetBSD $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef _UDF_SUBR_H_
#define _UDF_SUBR_H_
/* device information updating */
int udf_update_trackinfo(struct udf_mount *ump, struct mmc_trackinfo *trackinfo);
int udf_update_discinfo(struct udf_mount *ump);
/* tags and read/write descriptors */
int udf_check_tag(void *blob);
int udf_check_tag_payload(void *blob, uint32_t max_length);
int udf_validate_tag_sum(void *blob);
int udf_validate_tag_and_crc_sums(void *blob);
int udf_tagsize(union dscrptr *dscr, uint32_t udf_sector_size);
int udf_read_descriptor(
struct udf_mount *ump,
uint32_t sector,
struct malloc_type *mtype, /* where to allocate */
union dscrptr **dstp); /* out */
/* volume descriptors readers and checkers */
int udf_read_anchors(struct udf_mount *ump, struct udf_args *args);
int udf_read_vds_space(struct udf_mount *ump);
int udf_process_vds(struct udf_mount *ump, struct udf_args *args);
int udf_read_vds_tables(struct udf_mount *ump, struct udf_args *args);
int udf_read_rootdirs(struct udf_mount *ump, struct udf_args *args);
/* translation services */
int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, uint32_t *lb_numres, uint32_t *extres);
int udf_translate_file_extent(struct udf_node *node, uint32_t from, uint32_t pages, uint64_t *map);
/* node readers and writers */
int udf_get_node(struct udf_mount *ump, struct long_ad *icbloc, struct udf_node **noderes);
int udf_dispose_node(struct udf_node *node);
int udf_dispose_locked_node(struct udf_node *node);
void udf_read_filebuf(struct udf_node *node, struct buf *buf);
int udf_read_file_extent(struct udf_node *node, uint32_t from, uint32_t sectors, uint8_t *blob);
/* directory read and parse utils */
void udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp);
void unix_to_udf_name(char *result, char *name, uint8_t *result_len, struct charspec *chsp);
int udf_lookup_name_in_dir(struct vnode *vp, const char *name, int namelen, struct long_ad *icb_loc);
int udf_read_fid_stream(struct vnode *vp, uint64_t *offset, struct fileid_desc *fid, struct dirent *dirent);
/* vnode operations */
int udf_inactive(void *v);
int udf_reclaim(void *v);
int udf_readdir(void *v);
int udf_getattr(void *v);
int udf_setattr(void *v);
int udf_pathconf(void *v);
int udf_open(void *v);
int udf_close(void *v);
int udf_access(void *v);
int udf_read(void *v);
int udf_write(void *v);
int udf_trivial_bmap(void *v);
int udf_strategy(void *v);
int udf_lookup(void *v);
int udf_create(void *v);
int udf_mknod(void *v);
int udf_link(void *);
int udf_symlink(void *v);
int udf_readlink(void *v);
int udf_rename(void *v);
int udf_remove(void *v);
int udf_mkdir(void *v);
int udf_rmdir(void *v);
int udf_fsync(void *v);
int udf_advlock(void *v);
/* helpers and converters */
long udf_calchash(struct long_ad *icbptr); /* for `inode' numbering */
uint32_t udf_getaccessmode(struct udf_node *node);
void udf_timestamp_to_timespec(struct udf_mount *ump, struct timestamp *timestamp, struct timespec *timespec);
#endif /* !_UDF_SUBR_H_ */

756
sys/fs/udf/udf_vfsops.c Normal file
View File

@ -0,0 +1,756 @@
/* $NetBSD $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: udf_vfsops.c,v 1.1 2006/02/02 15:19:16 reinoud Exp $");
#endif /* not lint */
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
#include "opt_compat_netbsd.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <fs/udf/ecma167-udf.h>
#include <fs/udf/udf_mount.h>
#include "udf.h"
#include "udf_subr.h"
#include "udf_bswap.h"
/* verbose levels of the udf filingsystem */
int udf_verbose = UDF_DEBUGGING;
/* malloc regions */
MALLOC_DEFINE(M_UDFMNT, "UDF mount", "UDF mount structures");
MALLOC_DEFINE(M_UDFVOLD, "UDF volspace", "UDF volume space descriptors");
MALLOC_DEFINE(M_UDFTEMP, "UDF temp", "UDF scrap space");
struct pool udf_node_pool;
/* supported functions predefined */
int udf_mountroot(void);
int udf_mount(struct mount *, const char *, void *, struct nameidata *, struct lwp *);
int udf_start(struct mount *, int, struct lwp *);
int udf_unmount(struct mount *, int, struct lwp *);
int udf_root(struct mount *, struct vnode **);
int udf_quotactl(struct mount *, int, uid_t, void *, struct lwp *);
int udf_statvfs(struct mount *, struct statvfs *, struct lwp *);
int udf_sync(struct mount *, int, struct ucred *, struct lwp *);
int udf_vget(struct mount *, ino_t, struct vnode **);
int udf_fhtovp(struct mount *, struct fid *, struct vnode **);
int udf_checkexp(struct mount *, struct mbuf *, int *, struct ucred **);
int udf_vptofh(struct vnode *, struct fid *);
int udf_snapshot(struct mount *, struct vnode *, struct timespec *);
void udf_init(void);
void udf_reinit(void);
void udf_done(void);
/* internal functions */
static int udf_mountfs(struct vnode *, struct mount *, struct lwp *, struct udf_args *);
#if 0
static int update_mp(struct mount *, struct udf_args *);
#endif
/* handies */
#define VFSTOUDF(mp) ((struct udf_mount *)mp->mnt_data)
/* --------------------------------------------------------------------- */
/* predefine vnode-op list descriptor */
extern const struct vnodeopv_desc udf_vnodeop_opv_desc;
const struct vnodeopv_desc * const udf_vnodeopv_descs[] = {
&udf_vnodeop_opv_desc,
NULL,
};
/* vfsops descriptor linked in as anchor point for the filingsystem */
struct vfsops udf_vfsops = {
MOUNT_UDF, /* vfs_name */
udf_mount,
udf_start,
udf_unmount,
udf_root,
udf_quotactl,
udf_statvfs,
udf_sync,
udf_vget,
udf_fhtovp,
udf_vptofh,
udf_init,
udf_reinit,
udf_done,
udf_mountroot,
udf_snapshot,
vfs_stdextattrctl,
udf_vnodeopv_descs,
/* int vfs_refcount */
/* LIST_ENTRY(vfsops) */
};
VFS_ATTACH(udf_vfsops);
/* --------------------------------------------------------------------- */
/* file system starts here */
void
udf_init(void)
{
size_t size;
#ifdef _LKM
malloc_type_attach(M_UDFMNT);
malloc_type_attach(M_UDFVOLD);
malloc_type_attach(M_UDFTEMP);
#endif
/* init hashtables and pools */
size = sizeof(struct udf_node);
pool_init(&udf_node_pool, size, 0, 0, 0, "udf_node_pool", NULL);
}
/* --------------------------------------------------------------------- */
void
udf_reinit(void)
{
/* recreate hashtables */
/* reinit pool? */
}
/* --------------------------------------------------------------------- */
void
udf_done(void)
{
/* remove hashtables and pools */
pool_destroy(&udf_node_pool);
#ifdef _LKM
malloc_type_detach(M_UDFMNT);
malloc_type_detach(M_UDFVOLD);
malloc_type_detach(M_UDFTEMP);
#endif
}
/* --------------------------------------------------------------------- */
int
udf_mountroot(void)
{
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
#define MPFREE(a, lst) \
if ((a)) free((a), lst);
static void
free_udf_mountinfo(struct mount *mp)
{
struct udf_mount *ump;
int i;
ump = VFSTOUDF(mp);
if (ump) {
mp->mnt_data = NULL;
for (i = 0; i < UDF_ANCHORS; i++)
MPFREE(ump->anchors[i], M_UDFVOLD);
MPFREE(ump->primary_vol, M_UDFVOLD);
MPFREE(ump->logical_vol, M_UDFVOLD);
MPFREE(ump->unallocated, M_UDFVOLD);
MPFREE(ump->implementation, M_UDFVOLD);
MPFREE(ump->logvol_integrity, M_UDFVOLD);
for (i = 0; i < UDF_PARTITIONS; i++)
MPFREE(ump->partitions[i], M_UDFVOLD);
MPFREE(ump->fileset_desc, M_UDFVOLD);
MPFREE(ump->vat_table, M_UDFVOLD);
MPFREE(ump->sparing_table, M_UDFVOLD);
/*
* Note that the node related (e)fe descriptors pool is
* destroyed allready if it was used.
*/
free(ump, M_UDFMNT);
};
}
#undef MPFREE
/* --------------------------------------------------------------------- */
int
udf_mount(struct mount *mp, const char *path,
void *data, struct nameidata *ndp, struct lwp *l)
{
struct udf_args args;
struct udf_mount *ump;
struct vnode *devvp;
struct proc *p;
int openflags, accessmode, error;
DPRINTF(CALL, ("udf_mount called\n"));
p = l->l_proc;
if (mp->mnt_flag & MNT_GETARGS) {
/* request for the mount arguments */
ump = VFSTOUDF(mp);
if (ump == NULL)
return EINVAL;
return copyout(&ump->mount_args, data, sizeof(args));
};
/* handle request for updating mount parameters */
/* TODO can't update my mountpoint yet */
if (mp->mnt_flag & MNT_UPDATE) {
return EOPNOTSUPP;
};
/* OK, so we are asked to mount the device/file! */
error = copyin(data, &args, sizeof(struct udf_args));
if (error)
return error;
/* check/translate struct version */
/* TODO sanity checking other mount arguments */
if (args.version != 1) {
printf("mount_udf: unrecognized argument structure version\n");
return EINVAL;
};
/* lookup name to get its vnode */
NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args.fspec, l);
error = namei(ndp);
if (error)
return error;
/* devvp is *locked* now */
devvp = ndp->ni_vp;
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_VOLUMES)
vprint("UDF mount, trying to mount \n", devvp);
#endif
/* check if its a block device specified */
if (devvp->v_type != VBLK) {
vrele(devvp);
return ENOTBLK;
}
if (bdevsw_lookup(devvp->v_rdev) == NULL) {
vrele(devvp);
return ENXIO;
}
/* force read-only for now */
mp->mnt_flag |= MNT_RDONLY;
/*
* If mount by non-root, then verify that user has necessary
* permissions on the device.
*/
if (p->p_ucred->cr_uid != 0) {
accessmode = VREAD;
if ((mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
error = VOP_ACCESS(devvp, accessmode, p->p_ucred, l);
if (error) {
vput(devvp);
return (error);
}
}
/*
* Disallow multiple mounts of the same device. Disallow mounting of
* a device that is currently in use (except for root, which might
* share swap device for miniroot).
*/
error = vfs_mountedon(devvp);
if (error) {
vput(devvp);
return error;
};
if ((vcount(devvp) > 1) && (devvp != rootvp)) {
vput(devvp);
return EBUSY;
}
/*
* Open device and try to mount it!
*/
if (mp->mnt_flag & MNT_RDONLY) {
openflags = FREAD;
} else {
openflags = FREAD | FWRITE;
};
error = VOP_OPEN(devvp, openflags, FSCRED, l);
if (error == 0) {
/* opened ok, try mounting */
error = udf_mountfs(devvp, mp, l, &args);
if (error) {
free_udf_mountinfo(mp);
/* devvp is still locked */
(void) VOP_CLOSE(devvp, openflags, NOCRED, l);
};
};
if (error) {
/* devvp is still locked */
vput(devvp);
return error;
};
/* register our mountpoint being on this device */
devvp->v_specmountpoint = mp;
/* successfully mounted */
DPRINTF(VOLUMES, ("udf_mount() successfull\n"));
/* unlock it but dont deref it */
VOP_UNLOCK(devvp, 0);
return set_statvfs_info(path, UIO_USERSPACE, args.fspec, UIO_USERSPACE, mp, l);
}
/* --------------------------------------------------------------------- */
#ifdef DEBUG
static void
udf_unmount_sanity_check(struct mount *mp)
{
struct vnode *vp;
printf("On unmount, i found the following nodes:\n");
LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
vprint("", vp);
if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) {
printf(" is locked\n");
};
if (vp->v_usecount > 1)
printf(" more than one usecount %d\n", vp->v_usecount);
};
}
#endif
int
udf_unmount(struct mount *mp, int mntflags, struct lwp *l)
{
struct udf_mount *ump;
int error, flags, closeflags;
DPRINTF(CALL, ("udf_umount called\n"));
/*
* By specifying SKIPSYSTEM we can skip vnodes marked with VSYSTEM.
* This hardly documented feature allows us to exempt certain files
* from being flushed.
*/
flags = SKIPSYSTEM; /* allow for system vnodes to stay alive */
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
ump = VFSTOUDF(mp);
if (!ump)
panic("UDF unmount: empty ump\n");
/* TODO remove these paranoid functions */
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
if ((error = vflush(mp, NULLVP, flags)) != 0)
return error;
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
DPRINTF(VOLUMES, ("flush OK\n"));
/*
* TODO close logical volume and close session if requested.
*
* XXX no system nodes defined yet. Code to reclaim them is calling
* VOP_RECLAIM on the nodes themselves.
*/
/* dispose of our descriptor pool */
pool_destroy(&ump->desc_pool);
/* close device */
DPRINTF(VOLUMES, ("closing device\n"));
if (mp->mnt_flag & MNT_RDONLY) {
closeflags = FREAD;
} else {
closeflags = FREAD | FWRITE;
};
/* devvp is still locked by us */
vn_lock(ump->devvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_CLOSE(ump->devvp, closeflags, NOCRED, l);
if (error)
printf("Error during closure of device! error %d, "
"device might stay locked\n", error);
DPRINTF(VOLUMES, ("device close ok\n"));
/* clear our mount reference and release device node */
ump->devvp->v_specmountpoint = NULL;
vput(ump->devvp);
/* free ump struct */
mp->mnt_data = NULL;
mp->mnt_flag &= ~MNT_LOCAL;
/* free up umt structure */
free_udf_mountinfo(mp);
DPRINTF(VOLUMES, ("Fin unmount\n"));
return error;
}
/* --------------------------------------------------------------------- */
/*
* Helper function of udf_mount() that actually mounts the disc.
*/
static int
udf_mountfs(struct vnode *devvp, struct mount *mp,
struct lwp *l, struct udf_args *args)
{
struct udf_mount *ump;
uint32_t sector_size, lb_size, bshift;
int num_anchors, error, lst;
/* flush out any old buffers remaining from a previous use. */
error = vinvalbuf(devvp, V_SAVE, l->l_proc->p_ucred, l, 0, 0);
if (error)
return error;
/* allocate udf part of mount structure; malloc allways succeeds */
ump = malloc(sizeof(struct udf_mount), M_UDFMNT, M_WAITOK);
memset(ump, 0, sizeof(struct udf_mount));
/* init locks */
simple_lock_init(&ump->ihash_slock);
lockinit(&ump->get_node_lock, PINOD, "udf_getnode", 0, 0);
/* init `ino_t' to udf_node hash table */
for (lst = 0; lst < UDF_INODE_HASHSIZE; lst++) {
LIST_INIT(&ump->udf_nodes[lst]);
};
/* set up linkage */
mp->mnt_data = ump;
ump->vfs_mountp = mp;
/* set up arguments and device */
ump->mount_args = *args;
ump->devvp = devvp;
error = udf_update_discinfo(ump);
if (error) {
printf("UDF mount: error inspecting fs node\n");
return error;
};
/* inspect sector size */
sector_size = ump->discinfo.sector_size;
bshift = 1;
while ((1 << bshift) < sector_size)
bshift++;
if ((1 << bshift) != sector_size) {
printf("UDF mount: "
"hit NetBSD implementation fence on sector size\n");
return EIO;
};
/* read all anchors to get volume descriptor sequence */
num_anchors = udf_read_anchors(ump, args);
if (num_anchors == 0)
return ENOENT;
DPRINTF(VOLUMES, ("Read %d anchors on this disc, session %d\n",
num_anchors, args->sessionnr));
/* read in volume descriptor sequence */
error = udf_read_vds_space(ump);
if (error)
printf("UDF mount: error reading volume space\n");
/* check consistency and completeness */
if (!error) {
error = udf_process_vds(ump, args);
if (error)
printf("UDF mount: disc not properly formatted\n");
};
/*
* Initialise pool for descriptors associated with nodes. This is done
* in lb_size units though currently lb_size is dictated to be
* sector_size.
*/
lb_size = udf_rw32(ump->logical_vol->lb_size);
pool_init(&ump->desc_pool, lb_size, 0, 0, 0, "udf_desc_pool", NULL);
/* read vds support tables like VAT, sparable etc. */
if (!error) {
error = udf_read_vds_tables(ump, args);
if (error)
printf("UDF mount: error in format or damaged disc\n");
};
if (!error) {
error = udf_read_rootdirs(ump, args);
if (error)
printf("UDF mount: "
"disc not properly formatted or damaged disc\n");
};
if (error)
return error;
/* setup rest of mount information */
mp->mnt_data = ump;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_UDF);
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = UDF_MAX_NAMELEN;
mp->mnt_flag |= MNT_LOCAL;
/* bshift is allways equal to disc sector size */
mp->mnt_dev_bshift = bshift;
mp->mnt_fs_bshift = bshift;
/* do we have to set this? */
devvp->v_specmountpoint = mp;
/* success! */
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_start(struct mount *mp, int flags, struct lwp *l)
{
/* do we have to do something here? */
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_root(struct mount *mp, struct vnode **vpp)
{
struct vnode *vp;
struct long_ad *dir_loc;
struct udf_mount *ump = VFSTOUDF(mp);
struct udf_node *root_dir;
int error;
DPRINTF(CALL, ("udf_root called\n"));
dir_loc = &ump->fileset_desc->rootdir_icb;
error = udf_get_node(ump, dir_loc, &root_dir);
if (!root_dir)
error = ENOENT;
if (error)
return error;
vp = root_dir->vnode;
simple_lock(&vp->v_interlock);
root_dir->vnode->v_flag |= VROOT;
simple_unlock(&vp->v_interlock);
*vpp = vp;
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_quotactl(struct mount *mp, int cmds, uid_t uid, void *arg, struct lwp *l)
{
DPRINTF(NOTIMPL, ("udf_quotactl called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
int
udf_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
{
struct udf_mount *ump = VFSTOUDF(mp);
struct logvol_int_desc *lvid;
struct udf_logvol_info *impl;
uint64_t freeblks, sizeblks;
uint32_t *pos1, *pos2;
int part, num_part;
DPRINTF(CALL, ("udf_statvfs called\n"));
sbp->f_flag = mp->mnt_flag;
sbp->f_bsize = ump->discinfo.sector_size;
sbp->f_frsize = ump->discinfo.sector_size;
sbp->f_iosize = ump->discinfo.sector_size;
/* TODO integrity locking */
/* free and used space for mountpoint based on logvol integrity */
lvid = ump->logvol_integrity;
if (lvid) {
num_part = udf_rw32(lvid->num_part);
impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
freeblks = sizeblks = 0;
for (part=0; part < num_part; part++) {
pos1 = &lvid->tables[0] + part;
pos2 = &lvid->tables[0] + num_part + part;
if (udf_rw32(*pos1) != (uint32_t) -1) {
freeblks += udf_rw32(*pos1);
sizeblks += udf_rw32(*pos2);
};
};
sbp->f_blocks = sizeblks;
sbp->f_bfree = freeblks;
sbp->f_files = udf_rw32(impl->num_files);
sbp->f_files += udf_rw32(impl->num_directories);
/* XXX read only for now XXX */
sbp->f_bavail = 0;
sbp->f_bresvd = 0;
/* tricky, next only aplies to ffs i think, so set to zero */
sbp->f_ffree = 0;
sbp->f_favail = 0;
sbp->f_fresvd = 0;
};
copy_statvfs_info(sbp, mp);
return 0;
}
/* --------------------------------------------------------------------- */
int
udf_sync(struct mount *mp, int waitfor, struct ucred *cred, struct lwp *p)
{
DPRINTF(CALL, ("udf_sync called\n"));
/* nothing to be done as upto now read-only */
return 0;
}
/* --------------------------------------------------------------------- */
/*
* Get vnode for the file system type specific file id ino for the fs. Its
* used for reference to files by unique ID and for NFSv3.
* (optional) TODO lookup why some sources state NFSv3
*/
int
udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
DPRINTF(NOTIMPL, ("udf_vget called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
/*
* Lookup vnode for file handle specified
*/
int
udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
{
DPRINTF(NOTIMPL, ("udf_fhtovp called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
/*
* Create an unique file handle. Its structure is opaque and won't be used by
* other subsystems. It should uniquely identify the file in the filingsystem
* and enough information to know if a file has been removed and/or resources
* have been recycled.
*/
int
udf_vptofh(struct vnode *vp, struct fid *fid)
{
DPRINTF(NOTIMPL, ("udf_vptofh called\n"));
return EOPNOTSUPP;
}
/* --------------------------------------------------------------------- */
/*
* Create a filingsystem snapshot at the specified timestamp. Could be
* implemented by explicitly creating a new session or with spare room in the
* integrity descriptor space
*/
int
udf_snapshot(struct mount *mp, struct vnode *vp, struct timespec *tm)
{
DPRINTF(NOTIMPL, ("udf_snapshot called\n"));
return EOPNOTSUPP;
}

1274
sys/fs/udf/udf_vnops.c Normal file

File diff suppressed because it is too large Load Diff

12
sys/lkm/vfs/udf/Makefile Normal file
View File

@ -0,0 +1,12 @@
# $NetBSD: Makefile,v 1.1 2006/02/02 15:19:16 reinoud Exp $
.include "../Makefile.inc"
.PATH: $S/fs/udf ${.CURDIR}/..
KMOD= udf
SRCS= lkminit_vfs.c
SRCS+= udf_osta.c udf_subr.c udf_vfsops.c udf_vnops.c
.include <bsd.kmod.mk>

View File

@ -0,0 +1,80 @@
/* $NetBSD: lkminit_vfs.c,v 1.1 2006/02/02 15:19:16 reinoud Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Michael Graff <explorer@flame.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lkminit_vfs.c,v 1.1 2006/02/02 15:19:16 reinoud Exp $");
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <fs/udf/udf_mount.h>
int udf_lkmentry __P((struct lkm_table *, int, int));
/*
* This is the vfsops table for the file system in question
*/
extern struct vfsops udf_vfsops;
/*
* declare the filesystem
*/
MOD_VFS("udf", -1, &udf_vfsops);
/*
* entry point
*/
int
udf_lkmentry(lkmtp, cmd, ver)
struct lkm_table *lkmtp;
int cmd;
int ver;
{
DISPATCH(lkmtp, cmd, ver, lkm_nofunc, lkm_nofunc, lkm_nofunc);
}