diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2009-08-14 22:23:46 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2009-08-14 22:23:46 +0000 |
commit | 4f8bb894710e6a2cc1f46b6a005873875815e6e7 (patch) | |
tree | dae566b4d01676a1702f3c3ef9af734343c15e17 /sys | |
parent | 9baabc7a1abe127297baad825172a45c4d172b78 (diff) |
First cut at UDF 2.[56] support, allowing read-only access to HDDVD
and Blu-ray disks. Previously working DVDs should still work.
Done at f2k9 with phessler@. Vnode bug squashing by beck@. Thanks
to Bryan Brake for sending HDDVD/Blu-ray hardware and disks to f2k9
in Stockholm.
ok beck@ dlg@ phessler@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/isofs/udf/udf.h | 9 | ||||
-rw-r--r-- | sys/isofs/udf/udf_vfsops.c | 137 | ||||
-rw-r--r-- | sys/isofs/udf/udf_vnops.c | 123 |
3 files changed, 213 insertions, 56 deletions
diff --git a/sys/isofs/udf/udf.h b/sys/isofs/udf/udf.h index 1d8ecb758c1..bd049a50d3e 100644 --- a/sys/isofs/udf/udf.h +++ b/sys/isofs/udf/udf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: udf.h,v 1.12 2007/12/09 20:54:01 jmc Exp $ */ +/* $OpenBSD: udf.h,v 1.13 2009/08/14 22:23:45 krw Exp $ */ /* * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> @@ -46,7 +46,7 @@ struct unode { long u_diroff; long u_vatlen; } un_u; - struct file_entry *u_fentry; + struct extfile_entry *u_fentry; }; #define u_diroff un_u.u_diroff @@ -61,7 +61,11 @@ struct umount { int um_bshift; int um_bmask; uint32_t um_start; + uint32_t um_realstart; uint32_t um_len; + uint32_t um_reallen; + uint32_t um_meta_start; + uint32_t um_meta_len; struct unode *um_vat; struct long_ad um_root_icb; LIST_HEAD(udf_hash_lh, unode) *um_hashtbl; @@ -74,6 +78,7 @@ struct umount { #define UDF_MNT_FIND_VAT 0x01 /* Indicates a VAT must be found */ #define UDF_MNT_USES_VAT 0x02 /* Indicates a VAT must be used */ +#define UDF_MNT_USES_META 0x04 /* Indicates we are using a Metadata partition*/ struct udf_dirstream { struct unode *node; diff --git a/sys/isofs/udf/udf_vfsops.c b/sys/isofs/udf/udf_vfsops.c index 85bf2556eb2..4a1ac754931 100644 --- a/sys/isofs/udf/udf_vfsops.c +++ b/sys/isofs/udf/udf_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udf_vfsops.c,v 1.29 2009/07/09 22:29:56 thib Exp $ */ +/* $OpenBSD: udf_vfsops.c,v 1.30 2009/08/14 22:23:45 krw Exp $ */ /* * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> @@ -79,6 +79,7 @@ struct pool udf_ds_pool; int udf_find_partmaps(struct umount *, struct logvol_desc *); int udf_get_vpartmap(struct umount *, struct part_map_virt *); int udf_get_spartmap(struct umount *, struct part_map_spare *); +int udf_get_mpartmap(struct umount *, struct part_map_meta *); int udf_mountfs(struct vnode *, struct mount *, uint32_t, struct proc *); const struct vfsops udf_vfsops = { @@ -220,7 +221,8 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) struct part_desc *pd; struct logvol_desc *lvd; struct fileset_desc *fsd; - struct file_entry *root_fentry; + struct extfile_entry *xfentry; + struct file_entry *fentry; uint32_t sector, size, mvds_start, mvds_end; uint32_t fsd_offset = 0; uint16_t part_num = 0, fsd_part = 0; @@ -305,8 +307,8 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { part_found = 1; part_num = letoh16(pd->part_num); - ump->um_len = letoh32(pd->part_len); - ump->um_start = letoh32(pd->start_loc); + ump->um_len = ump->um_reallen = letoh32(pd->part_len); + ump->um_start = ump->um_realstart = letoh32(pd->start_loc); } brelse(bp); @@ -320,7 +322,34 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) goto bail; } - if (fsd_part != part_num) { + if (ISSET(ump->um_flags, UDF_MNT_USES_META)) { + /* Read Metadata File 'File Entry' to find Metadata file. */ + struct long_ad *la; + sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */ + if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) { + printf("Cannot read sector %d for Metadata File Entry\n", sector); + error = EINVAL; + goto bail; + } + xfentry = (struct extfile_entry *)bp->b_data; + fentry = (struct file_entry *)bp->b_data; + if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) + la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)]; + else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0) + la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)]; + else { + printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n", + sector, fentry->tag.id); + error = EINVAL; + goto bail; + } + ump->um_meta_start = letoh32(la->loc.lb_num); + ump->um_meta_len = letoh32(la->len); + if (bp != NULL) { + brelse(bp); + bp = NULL; + } + } else if (fsd_part != part_num) { printf("FSD does not lie within the partition!\n"); error = EINVAL; goto bail; @@ -342,7 +371,11 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing * me in the right direction here. */ - sector = fsd_offset; + + if (ISSET(ump->um_flags, UDF_MNT_USES_META)) + sector = ump->um_meta_start; + else + sector = fsd_offset; udf_vat_map(ump, §or); if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) { printf("Cannot read sector %d of FSD\n", sector); @@ -353,6 +386,10 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) fsd_found = 1; bcopy(&fsd->rootdir_icb, &ump->um_root_icb, sizeof(struct long_ad)); + if (ISSET(ump->um_flags, UDF_MNT_USES_META)) { + ump->um_root_icb.loc.lb_num += ump->um_meta_start; + ump->um_root_icb.loc.part_num = part_num; + } } brelse(bp); @@ -375,10 +412,15 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) 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; + xfentry = (struct extfile_entry *)bp->b_data; + fentry = (struct file_entry *)bp->b_data; + error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY); + if (error) { + error = udf_checktag(&fentry->tag, TAGID_FENTRY); + if (error) { + printf("Invalid root file entry!\n"); + goto bail; + } } brelse(bp); @@ -507,8 +549,9 @@ udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) struct vnode *devvp; struct umount *ump; struct proc *p; - struct vnode *vp; + struct vnode *vp, *nvp; struct unode *up; + struct extfile_entry *xfe; struct file_entry *fe; int error, sector, size; @@ -543,24 +586,36 @@ udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) return (error); } + xfe = (struct extfile_entry *)bp->b_data; fe = (struct file_entry *)bp->b_data; - if (udf_checktag(&fe->tag, TAGID_FENTRY)) { - printf("Invalid file entry!\n"); - pool_put(&unode_pool, up); - brelse(bp); - return (ENOMEM); + error = udf_checktag(&xfe->tag, TAGID_EXTFENTRY); + if (error == 0) { + size = letoh32(xfe->l_ea) + letoh32(xfe->l_ad); + } else { + error = udf_checktag(&fe->tag, TAGID_FENTRY); + if (error) { + printf("Invalid file entry!\n"); + pool_put(&unode_pool, up); + if (bp != NULL) + brelse(bp); + return (ENOMEM); + } else + size = letoh32(fe->l_ea) + letoh32(fe->l_ad); } - size = UDF_FENTRY_SIZE + letoh32(fe->l_ea) + letoh32(fe->l_ad); - - up->u_fentry = malloc(size, M_UDFFENTRY, M_NOWAIT); + /* Allocate max size of FE/XFE. */ + up->u_fentry = malloc(size + UDF_EXTFENTRY_SIZE, M_UDFFENTRY, M_NOWAIT | M_ZERO); if (up->u_fentry == NULL) { pool_put(&unode_pool, up); - brelse(bp); + if (bp != NULL) + brelse(bp); return (ENOMEM); /* Cannot allocate file entry block */ } - bcopy(bp->b_data, up->u_fentry, size); + if (udf_checktag(&xfe->tag, TAGID_EXTFENTRY) == 0) + bcopy(bp->b_data, up->u_fentry, size + UDF_EXTFENTRY_SIZE); + else + bcopy(bp->b_data, up->u_fentry, size + UDF_FENTRY_SIZE); brelse(bp); bp = NULL; @@ -588,14 +643,12 @@ udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) switch (up->u_fentry->icbtag.file_type) { default: - vp->v_type = VBAD; + printf("Unrecognized file type (%d)\n", vp->v_type); + vp->v_type = VREG; break; case UDF_ICB_FILETYPE_DIRECTORY: vp->v_type = VDIR; break; - case UDF_ICB_FILETYPE_RANDOMACCESS: - vp->v_type = VREG; - break; case UDF_ICB_FILETYPE_BLOCKDEVICE: vp->v_type = VBLK; break; @@ -611,11 +664,32 @@ udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) case UDF_ICB_FILETYPE_SYMLINK: vp->v_type = VLNK; break; + case UDF_ICB_FILETYPE_RANDOMACCESS: + case UDF_ICB_FILETYPE_REALTIME: case UDF_ICB_FILETYPE_UNKNOWN: vp->v_type = VREG; break; } + /* check if this is a vnode alias */ + if ((nvp = checkalias(vp, up->u_dev, ump->um_mountp)) != NULL) { + printf("found a vnode alias\n"); + /* + * Discard unneeded vnode, but save its udf_node. + * Note that the lock is carried over in the udf_node + */ + nvp->v_data = vp->v_data; + vp->v_data = NULL; + vp->v_op = spec_vnodeop_p; + vrele(vp); + vgone(vp); + /* + * Reinitialize aliased inode. + */ + vp = nvp; + ump->um_devvp = vp; + } + *vpp = vp; return (0); @@ -711,6 +785,7 @@ udf_get_spartmap(struct umount *ump, struct part_map_spare *pms) bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size)); brelse(bp); + bp = NULL; if (udf_checktag(&ump->um_stbl->tag, 0)) { free(ump->um_stbl, M_UDFMOUNT); @@ -730,6 +805,14 @@ udf_get_spartmap(struct umount *ump, struct part_map_spare *pms) return (0); } +/* Handle a metadata partition map */ +int +udf_get_mpartmap(struct umount *ump, struct part_map_meta *pmm) +{ + ump->um_flags |= UDF_MNT_USES_META; + ump->um_meta_start = pmm->meta_file_lbn; + return (0); +} /* Scan the partition maps */ int @@ -769,6 +852,10 @@ udf_find_partmaps(struct umount *ump, struct logvol_desc *lvd) UDF_REGID_ID_SIZE)) error = udf_get_spartmap(ump, (struct part_map_spare *) pmap); + else if (!bcmp(®id_id[0], "*UDF Metadata Partition", + UDF_REGID_ID_SIZE)) + error = udf_get_mpartmap(ump, + (struct part_map_meta *) pmap); else return (EINVAL); /* Unsupported partition map */ diff --git a/sys/isofs/udf/udf_vnops.c b/sys/isofs/udf/udf_vnops.c index 623067f502d..d29e0bcae83 100644 --- a/sys/isofs/udf/udf_vnops.c +++ b/sys/isofs/udf/udf_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udf_vnops.c,v 1.37 2009/08/13 15:00:14 jasper Exp $ */ +/* $OpenBSD: udf_vnops.c,v 1.38 2009/08/14 22:23:45 krw Exp $ */ /* * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> @@ -310,6 +310,7 @@ udf_getattr(void *v) struct vnode *vp; struct unode *up; struct vattr *vap; + struct extfile_entry *xfentry; struct file_entry *fentry; struct timespec ts; @@ -318,7 +319,9 @@ udf_getattr(void *v) vp = ap->a_vp; vap = ap->a_vap; up = VTOU(vp); - fentry = up->u_fentry; + + xfentry = up->u_fentry; + fentry = (struct file_entry *)up->u_fentry; vap->va_fsid = up->u_dev; vap->va_fileid = up->u_ino; @@ -330,9 +333,6 @@ udf_getattr(void *v) */ vap->va_uid = (letoh32(fentry->uid) == -1) ? 0 : letoh32(fentry->uid); vap->va_gid = (letoh32(fentry->gid) == -1) ? 0 : letoh32(fentry->gid); - udf_timetotimespec(&fentry->atime, &vap->va_atime); - udf_timetotimespec(&fentry->mtime, &vap->va_mtime); - vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */ vap->va_rdev = 0; if (vp->v_type & VDIR) { vap->va_nlink++; /* Count a reference to ourselves */ @@ -342,15 +342,23 @@ udf_getattr(void *v) * that directories consume at least one logical block, * make it appear so. */ - if (fentry->logblks_rec != 0) { + vap->va_size = up->u_ump->um_bsize; + } else + vap->va_size = letoh64(fentry->inf_len); + if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { + udf_timetotimespec(&xfentry->atime, &vap->va_atime); + udf_timetotimespec(&xfentry->mtime, &vap->va_mtime); + if ((vp->v_type & VDIR) && xfentry->logblks_rec != 0) vap->va_size = - letoh64(fentry->logblks_rec) * up->u_ump->um_bsize; - } else { - vap->va_size = up->u_ump->um_bsize; - } + letoh64(xfentry->logblks_rec) * up->u_ump->um_bsize; } else { - vap->va_size = letoh64(fentry->inf_len); + udf_timetotimespec(&fentry->atime, &vap->va_atime); + udf_timetotimespec(&fentry->mtime, &vap->va_mtime); + if ((vp->v_type & VDIR) && fentry->logblks_rec != 0) + vap->va_size = + letoh64(fentry->logblks_rec) * up->u_ump->um_bsize; } + vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */ vap->va_flags = 0; vap->va_gen = 1; vap->va_blocksize = up->u_ump->um_bsize; @@ -437,8 +445,10 @@ udf_read(void *v) error = udf_readatoffset(up, &size, offset, &bp, &data); if (error == 0) error = uiomove(data, size, uio); - if (bp != NULL) + if (bp != NULL) { brelse(bp); + bp = NULL; + } if (error) break; }; @@ -579,8 +589,10 @@ udf_getfid(struct udf_dirstream *ds) &ds->bp, &ds->data); if (error) { ds->error = error; - if (ds->bp != NULL) + if (ds->bp != NULL) { brelse(ds->bp); + ds->bp = NULL; + } return (NULL); } } @@ -622,8 +634,10 @@ udf_getfid(struct udf_dirstream *ds) /* Reduce all of the casting magic */ fid = (struct fileid_desc*)ds->buf; - if (ds->bp != NULL) + if (ds->bp != NULL) { brelse(ds->bp); + ds->bp = NULL; + } /* Fetch the next allocation */ ds->offset += ds->size; @@ -632,6 +646,10 @@ udf_getfid(struct udf_dirstream *ds) &ds->bp, &ds->data); if (error) { ds->error = error; + if (ds->bp != NULL) { + brelse(ds->bp); + ds->bp = NULL; + } return (NULL); } @@ -680,8 +698,10 @@ static void udf_closedir(struct udf_dirstream *ds) { - if (ds->bp != NULL) + if (ds->bp != NULL) { brelse(ds->bp); + ds->bp = NULL; + } if (ds->fid_fragment && ds->buf != NULL) free(ds->buf, M_UDFFID); @@ -733,6 +753,10 @@ udf_readdir(void *v) * Iterate through the file id descriptors. Give the parent dir * entry special attention. */ + if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { + up->u_ump->um_start += up->u_ump->um_meta_start; + up->u_ump->um_len = up->u_ump->um_meta_len; + } ds = udf_opendir(up, uio->uio_offset, letoh64(up->u_fentry->inf_len), up->u_ump); @@ -740,7 +764,7 @@ udf_readdir(void *v) /* Should we return an error on a bad fid? */ if (udf_checktag(&fid->tag, TAGID_FID)) { - printf("Invalid FID tag\n"); + printf("Invalid FID tag (%d)\n", fid->tag.id); error = EIO; break; } @@ -802,6 +826,10 @@ udf_readdir(void *v) error = ds->error; udf_closedir(ds); + if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { + up->u_ump->um_start = up->u_ump->um_realstart; + up->u_ump->um_len = up->u_ump->um_reallen; + } if (ap->a_ncookies != NULL) { if (error) @@ -1026,6 +1054,10 @@ udf_lookup(void *v) nchstats.ncs_2passes++; } + if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { + up->u_ump->um_start += up->u_ump->um_meta_start; + up->u_ump->um_len = up->u_ump->um_meta_len; + } lookloop: ds = udf_opendir(up, offset, fsize, ump); @@ -1041,6 +1073,7 @@ lookloop: if (fid->file_char & UDF_FILE_CHAR_DEL) continue; +printf("name: '%s', file_char: %u\n", nameptr, fid->file_char); if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { if (flags & ISDOTDOT) { id = udf_getid(&fid->icb); @@ -1060,6 +1093,10 @@ lookloop: if (error) { udf_closedir(ds); + if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { + up->u_ump->um_start = up->u_ump->um_realstart; + up->u_ump->um_len = up->u_ump->um_reallen; + } return (error); } @@ -1106,6 +1143,10 @@ lookloop: cache_enter(dvp, *vpp, ap->a_cnp); udf_closedir(ds); + if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { + up->u_ump->um_start = up->u_ump->um_realstart; + up->u_ump->um_len = up->u_ump->um_reallen; + } return (error); } @@ -1166,6 +1207,7 @@ udf_readatoffset(struct unode *up, int *size, off_t offset, struct buf **bp, uint8_t **data) { struct umount *ump; + struct extfile_entry *xfentry = NULL; struct file_entry *fentry = NULL; struct buf *bp1; uint32_t max_size; @@ -1181,9 +1223,15 @@ udf_readatoffset(struct unode *up, int *size, off_t offset, * This error means that the file *data* is stored in the * allocation descriptor field of the file entry. */ - fentry = up->u_fentry; - *data = &fentry->data[letoh32(fentry->l_ea)]; - *size = letoh32(fentry->l_ad); + if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) { + xfentry = up->u_fentry; + *data = &xfentry->data[letoh32(xfentry->l_ea)]; + *size = letoh32(xfentry->l_ad); + } else { + fentry = (struct file_entry *)up->u_fentry; + *data = &fentry->data[letoh32(fentry->l_ea)]; + *size = letoh32(fentry->l_ad); + } return (0); } else if (error != 0) { return (error); @@ -1214,17 +1262,26 @@ udf_bmap_internal(struct unode *up, off_t offset, daddr64_t *sector, uint32_t *max_size) { struct umount *ump; + struct extfile_entry *xfentry; struct file_entry *fentry; void *icb; struct icb_tag *tag; uint32_t icblen = 0; daddr64_t lsector; int ad_offset, ad_num = 0; - int i, p_offset; + int i, p_offset, l_ea, l_ad; ump = up->u_ump; - fentry = up->u_fentry; + xfentry = up->u_fentry; + fentry = (struct file_entry *)up->u_fentry; tag = &fentry->icbtag; + if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { + l_ea = letoh32(xfentry->l_ea); + l_ad = letoh32(xfentry->l_ad); + } else { + l_ea = letoh32(fentry->l_ea); + l_ad = letoh32(fentry->l_ad); + } switch (letoh16(tag->strat_type)) { case 4: @@ -1249,12 +1306,17 @@ udf_bmap_internal(struct unode *up, off_t offset, daddr64_t *sector, do { offset -= icblen; ad_offset = sizeof(struct short_ad) * ad_num; - if (ad_offset > letoh32(fentry->l_ad)) { - printf("File offset out of bounds\n"); + if (ad_offset > l_ad) { + printf("SFile offset out of bounds (%d > %d)\n", + ad_offset, l_ad); return (EINVAL); } - icb = GETICB(short_ad, fentry, - letoh32(fentry->l_ea) + ad_offset); + + if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) + icb = GETICB(short_ad, xfentry, l_ea + ad_offset); + else + icb = GETICB(short_ad, fentry, l_ea + ad_offset); + icblen = GETICBLEN(short_ad, icb); ad_num++; } while(offset >= icblen); @@ -1274,12 +1336,15 @@ udf_bmap_internal(struct unode *up, off_t offset, daddr64_t *sector, do { offset -= icblen; ad_offset = sizeof(struct long_ad) * ad_num; - if (ad_offset > letoh32(fentry->l_ad)) { - printf("File offset out of bounds\n"); + if (ad_offset > l_ad) { + printf("LFile offset out of bounds (%d > %d)\n", + ad_offset, l_ad); return (EINVAL); } - icb = GETICB(long_ad, fentry, - letoh32(fentry->l_ea) + ad_offset); + if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) + icb = GETICB(long_ad, xfentry, l_ea + ad_offset); + else + icb = GETICB(long_ad, fentry, l_ea + ad_offset); icblen = GETICBLEN(long_ad, icb); ad_num++; } while(offset >= icblen); |