FreeBSD Bugzilla – Attachment 84915 Details for
Bug 120989
UDF (with DVD-RAM) isn't mountable/readable
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
udf.diff
udf.diff (text/plain), 15.81 KB, created by
Andriy Gapon
on 2008-04-15 20:08:53 UTC
(
hide
)
Description:
udf.diff
Filename:
MIME Type:
Creator:
Andriy Gapon
Created:
2008-04-15 20:08:53 UTC
Size:
15.81 KB
patch
obsolete
>diff --git a/sys/fs/udf/ecma167-udf.h b/sys/fs/udf/ecma167-udf.h >index 2d78758..7e64ac1 100644 >--- a/sys/fs/udf/ecma167-udf.h >+++ b/sys/fs/udf/ecma167-udf.h >@@ -42,7 +42,8 @@ enum { > TAGID_LOGVOL_INTEGRITY = 9, > TAGID_FSD = 256, > TAGID_FID = 257, >- TAGID_FENTRY = 261 >+ TAGID_FENTRY = 261, >+ TAGID_EXTFENTRY = 266 > }; > > /* Descriptor tag [3/7.2] */ >@@ -354,6 +355,54 @@ struct file_entry { > #define UDF_FENTRY_PERM_GRP_MASK 0xE0 > #define UDF_FENTRY_PERM_OWNER_MASK 0x1C00 > >+/* Extended File Entry [4/14.17] */ >+struct extfile_entry { >+ struct desc_tag tag; >+ struct icb_tag icbtag; >+ uint32_t uid; >+ uint32_t gid; >+ uint32_t perm; >+ uint16_t link_cnt; >+ uint8_t rec_format; >+ uint8_t rec_disp_attr; >+ uint32_t rec_len; >+ uint64_t inf_len; >+ uint64_t obj_size; >+ uint64_t logblks_rec; >+ struct timestamp atime; >+ struct timestamp mtime; >+ struct timestamp ctime; >+ struct timestamp attrtime; >+ uint32_t ckpoint; >+ uint32_t reserved1; >+ struct long_ad ex_attr_icb; >+ struct long_ad streamdir_icb; >+ struct regid imp_id; >+ uint64_t unique_id; >+ uint32_t l_ea; /* Length of extended attribute area */ >+ uint32_t l_ad; /* Length of allocation descriptors */ >+ uint8_t data[1]; >+} __packed; >+#define UDF_EXTFENTRY_SIZE 216 >+/* Given a pointer to file_entry or extfile_entry object and a field name >+ * the following macro produces a field of a correctly typed structure >+ * based on tag id of the entry. >+ * This is not needed for fields up to and including inf_len, but is a must >+ * for all following fields. >+ * This macro, obviosly, can work only for fields that are present in both >+ * structure types. >+ */ >+#define GET_FENTRY_FIELD(entry, field) \ >+ ((entry)->tag.id == TAGID_FENTRY ? \ >+ ((struct file_entry *)(entry))->field \ >+ : \ >+ ((struct extfile_entry *)(entry))->field) >+#define GET_FENTRY_FIELD_PTR(entry, field) \ >+ ((entry)->tag.id == TAGID_FENTRY ? \ >+ &((struct file_entry *)(entry))->field \ >+ : \ >+ &((struct extfile_entry *)(entry))->field) >+ > union dscrptr { > struct desc_tag tag; > struct anchor_vdp avdp; >@@ -364,11 +413,12 @@ union dscrptr { > struct fileset_desc fsd; > struct fileid_desc fid; > struct file_entry fe; >+ struct extfile_entry efe; > }; > > /* Useful defines */ > > #define GETICB(ad_type, fentry, offset) \ >- (struct ad_type *)&fentry->data[offset] >+ ((struct ad_type *)GET_FENTRY_FIELD_PTR(fentry, data[offset])) > > #define GETICBLEN(ad_type, icb) le32toh(((struct ad_type *)(icb))->len) >diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c >index 84d6776..4568031 100644 >--- a/sys/fs/udf/udf_vfsops.c >+++ b/sys/fs/udf/udf_vfsops.c >@@ -308,7 +308,7 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { > struct part_desc *pd; > struct logvol_desc *lvd; > struct fileset_desc *fsd; >- struct file_entry *root_fentry; >+ struct desc_tag *root_tag; > uint32_t sector, size, mvds_start, mvds_end; > uint32_t logical_secsize; > uint32_t fsd_offset = 0; >@@ -330,6 +330,11 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { > > bo = &devvp->v_bufobj; > >+ if (devvp->v_rdev->si_iosize_max != 0) >+ mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; >+ if (mp->mnt_iosize_max > MAXPHYS) >+ mp->mnt_iosize_max = MAXPHYS; >+ > /* XXX: should be M_WAITOK */ > MALLOC(udfmp, struct udf_mnt *, sizeof(struct udf_mnt), M_UDFMOUNT, > M_NOWAIT | M_ZERO); >@@ -475,8 +480,9 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { > goto bail; > } > >- root_fentry = (struct file_entry *)bp->b_data; >- if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) { >+ root_tag = (struct desc_tag *)bp->b_data; >+ if ((error = udf_checktag(root_tag, TAGID_FENTRY)) >+ && (error = udf_checktag(root_tag, TAGID_EXTFENTRY))) { > printf("Invalid root file entry!\n"); > goto bail; > } >@@ -590,7 +596,7 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) > struct thread *td; > struct vnode *vp; > struct udf_node *unode; >- struct file_entry *fe; >+ struct desc_tag *tag; > int error, sector, size; > > error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL); >@@ -637,18 +643,27 @@ udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) > return (error); > } > >- fe = (struct file_entry *)bp->b_data; >- if (udf_checktag(&fe->tag, TAGID_FENTRY)) { >+ tag = (struct desc_tag *)bp->b_data; >+ if (udf_checktag(tag, TAGID_FENTRY) == 0) { >+ struct file_entry *fe = (struct file_entry *)bp->b_data; >+ size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad); >+ } >+ else if (udf_checktag(tag, TAGID_EXTFENTRY) == 0) { >+ struct extfile_entry *efe = (struct extfile_entry *)bp->b_data; >+ size = UDF_EXTFENTRY_SIZE + le32toh(efe->l_ea) + le32toh(efe->l_ad); >+ } >+ else { > printf("Invalid file entry!\n"); > vgone(vp); > vput(vp); > brelse(bp); > *vpp = NULL; >- return (ENOMEM); >+ return (EINVAL); > } >- size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad); >+ > MALLOC(unode->fentry, struct file_entry *, size, M_UDFFENTRY, > M_NOWAIT | M_ZERO); >+ > if (unode->fentry == NULL) { > printf("Cannot allocate file entry block\n"); > vgone(vp); >diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c >index b77e571..29b5a66 100644 >--- a/sys/fs/udf/udf_vnops.c >+++ b/sys/fs/udf/udf_vnops.c >@@ -168,6 +168,21 @@ udf_open(struct vop_open_args *ap) { > struct udf_node *np = VTON(ap->a_vp); > off_t fsize; > >+ /* >+ * We currently do not support any other strategy type, so >+ * udf_bmap_internal, udf_bmap, udf_strategy would fail. >+ * I.e. we can not access content of this file anyway. >+ */ >+ if (le16toh(np->fentry->icbtag.strat_type) != 4) { >+ printf("Unsupported strategy type %d\n", le16toh(np->fentry->icbtag.strat_type)); >+ return EINVAL; >+ } >+ >+ if (np->fentry->tag.id == TAGID_EXTFENTRY && >+ np->fentry->inf_len != ((struct extfile_entry *)np->fentry)->obj_size) { >+ printf("Files with multiple streams are not supported\n"); >+ return EINVAL; >+ } > fsize = le64toh(np->fentry->inf_len); > vnode_create_vobject(ap->a_vp, fsize, ap->a_td); > return 0; >@@ -206,9 +221,13 @@ udf_timetotimespec(struct timestamp *time, struct timespec *t) > > t->tv_nsec = 0; > >- /* DirectCD seems to like using bogus year values */ >+ /* >+ * DirectCD seems to like using bogus year values. >+ * Distrust time->month especially, since it will be used for an >+ * array index. >+ */ > year = le16toh(time->year); >- if (year < 1970) { >+ if (year < 1970 || time->month > 12) { > t->tv_sec = 0; > return; > } >@@ -217,21 +236,14 @@ udf_timetotimespec(struct timestamp *time, struct timespec *t) > t->tv_sec = time->second; > t->tv_sec += time->minute * 60; > t->tv_sec += time->hour * 3600; >- t->tv_sec += time->day * 3600 * 24; >+ t->tv_sec += (time->day - 1) * 3600 * 24; > > /* Calculate the month */ > lpyear = udf_isaleapyear(year); > for (i = 1; i < time->month; i++) >- t->tv_sec += mon_lens[lpyear][i] * 3600 * 24; >- >- /* Speed up the calculation */ >- if (year > 1979) >- t->tv_sec += 315532800; >- if (year > 1989) >- t->tv_sec += 315619200; >- if (year > 1999) >- t->tv_sec += 315532800; >- for (i = 2000; i < year; i++) { >+ t->tv_sec += mon_lens[lpyear][i - 1] * 3600 * 24; >+ >+ for (i = 1970; i < year; i++) { > daysinyear = udf_isaleapyear(i) + 365 ; > t->tv_sec += daysinyear * 3600 * 24; > } >@@ -276,9 +288,16 @@ udf_getattr(struct vop_getattr_args *a) > */ > vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid); > vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid); >- udf_timetotimespec(&fentry->atime, &vap->va_atime); >- udf_timetotimespec(&fentry->mtime, &vap->va_mtime); >- vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */ >+ if (fentry->tag.id == TAGID_FENTRY) { >+ udf_timetotimespec(&fentry->atime, &vap->va_atime); >+ udf_timetotimespec(&fentry->mtime, &vap->va_mtime); >+ vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */ >+ } >+ else { /*TAGID_EXTFENTRY*/ >+ udf_timetotimespec(&((struct extfile_entry *)fentry)->atime, &vap->va_atime); >+ udf_timetotimespec(&((struct extfile_entry *)fentry)->mtime, &vap->va_atime); >+ udf_timetotimespec(&((struct extfile_entry *)fentry)->ctime, &vap->va_ctime); >+ } > vap->va_rdev = 0; /* XXX */ > if (vp->v_type & VDIR) { > /* >@@ -287,9 +306,9 @@ udf_getattr(struct vop_getattr_args *a) > * that directories consume at least one logical block, > * make it appear so. > */ >- if (fentry->logblks_rec != 0) { >+ if (GET_FENTRY_FIELD(fentry, logblks_rec) != 0) { > vap->va_size = >- le64toh(fentry->logblks_rec) * node->udfmp->bsize; >+ GET_FENTRY_FIELD(fentry, logblks_rec) * node->udfmp->bsize; > } else { > vap->va_size = node->udfmp->bsize; > } >@@ -343,7 +362,9 @@ udf_pathconf(struct vop_pathconf_args *a) > > #define lblkno(udfmp, loc) ((loc) >> (udfmp)->bshift) > #define blkoff(udfmp, loc) ((loc) & (udfmp)->bmask) >-#define lblktosize(imp, blk) ((blk) << (udfmp)->bshift) >+#define lblktosize(udfmp, blk) ((blk) << (udfmp)->bshift) >+ >+#define HAS_EMBEDDED_DATA(node) ((le16toh((node)->fentry->icbtag.flags) & 0x7) == 3) > > static int > udf_read(struct vop_read_args *ap) >@@ -362,6 +383,32 @@ udf_read(struct vop_read_args *ap) > return (0); > if (uio->uio_offset < 0) > return (EINVAL); >+ >+ if (HAS_EMBEDDED_DATA(node)) { >+ uint8_t *data; >+ >+ if (node->fentry->tag.id == TAGID_FENTRY) { >+ struct file_entry *fentry = node->fentry; >+ data = &fentry->data[le32toh(fentry->l_ea)]; >+ fsize = le32toh(fentry->l_ad); >+ } >+ else { >+ struct extfile_entry *fentry = (struct extfile_entry *)node->fentry; >+ data = &fentry->data[le32toh(fentry->l_ea)]; >+ fsize = le32toh(fentry->l_ad); >+ } >+ >+ n = uio->uio_resid; >+ diff = fsize - uio->uio_offset; >+ if (diff <= 0) >+ return (0); >+ if (diff < n) >+ n = diff; >+ >+ error = uiomove(data + uio->uio_offset, (int)n, uio); >+ return (error); >+ } >+ > fsize = le64toh(node->fentry->inf_len); > udfmp = node->udfmp; > do { >@@ -758,7 +805,8 @@ udf_readdir(struct vop_readdir_args *a) > ds->this_off); > } > if (error) { >- printf("uiomove returned %d\n", error); >+ if(error > 0) >+ printf("uiomove returned %d\n", error); > break; > } > >@@ -768,6 +816,8 @@ udf_readdir(struct vop_readdir_args *a) > *a->a_eofflag = uiodir.eofflag; > uio->uio_offset = ds->offset + ds->off; > >+ if(error < 0) >+ error = 0; > if (!error) > error = ds->error; > >@@ -799,10 +849,10 @@ udf_strategy(struct vop_strategy_args *a) > struct buf *bp; > struct vnode *vp; > struct udf_node *node; >+ struct bufobj *bo; > int maxsize; > daddr_t sector; >- struct bufobj *bo; >- int multiplier; >+ int error; > > bp = a->a_bp; > vp = a->a_vp; >@@ -813,24 +863,23 @@ udf_strategy(struct vop_strategy_args *a) > * Files that are embedded in the fentry don't translate well > * to a block number. Reject. > */ >- if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize, >- §or, &maxsize)) { >+ error = udf_bmap_internal(node, lblktosize(node->udfmp, bp->b_lblkno), §or, &maxsize); >+ if (error) { >+ if (error == UDF_INVALID_BMAP) >+ printf("udf_strategy called for file with data embedded in fentry\n"); > clrbuf(bp); > bp->b_blkno = -1; >+ bufdone(bp); >+ return (0); > } >- >- /* bmap gives sector numbers, bio works with device blocks */ >- multiplier = node->udfmp->bsize / DEV_BSIZE; >- bp->b_blkno = sector * multiplier; >- >- } >- if ((long)bp->b_blkno == -1) { >- bufdone(bp); >- return (0); >+ /* udf_bmap_internal gives sector numbers, bio works with device blocks */ >+ bp->b_blkno = sector << (node->udfmp->bshift - DEV_BSHIFT); > } >+ > bo = node->udfmp->im_bo; > bp->b_iooffset = dbtob(bp->b_blkno); > BO_STRATEGY(bo, bp); >+ > return (0); > } > >@@ -851,17 +900,43 @@ udf_bmap(struct vop_bmap_args *a) > if (a->a_runb) > *a->a_runb = 0; > >- error = udf_bmap_internal(node, a->a_bn * node->udfmp->bsize, &lsector, >- &max_size); >+ /* >+ * UDF_INVALID_BMAP means data embedded into fentry, this is an internal >+ * error that should not be propagated to calling code. >+ * Most obvious mapping for this error is EOPNOTSUPP as we can not truly >+ * translate block numbers in this case. >+ * Incidentally, this return code will make vnode pager to use VOP_READ >+ * to get data for mmap-ed pages and udf_read knows how to do the right >+ * thing for this kind of files. >+ */ >+ error = udf_bmap_internal(node, a->a_bn << node->udfmp->bshift, &lsector, &max_size); >+ if (error == UDF_INVALID_BMAP) >+ return EOPNOTSUPP; > if (error) > return (error); > > /* Translate logical to physical sector number */ > *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT); > >- /* Punt on read-ahead for now */ >- if (a->a_runp) >- *a->a_runp = 0; >+ /* >+ * Determine maximum number of readahead blocks following the >+ * requested block. >+ */ >+ if (a->a_runp) { >+ int nblk; >+ >+ nblk = (max_size >> node->udfmp->bshift) - 1; >+ if (nblk <= 0) >+ *a->a_runp = 0; >+ else if (nblk >= (MAXBSIZE >> node->udfmp->bshift)) >+ *a->a_runp = (MAXBSIZE >> node->udfmp->bshift) - 1; >+ else >+ *a->a_runp = nblk; >+ } >+ >+ if (a->a_runb) { >+ *a->a_runb = 0; >+ } > > return (0); > } >@@ -1052,7 +1127,6 @@ udf_readatoffset(struct udf_node *node, int *size, off_t offset, > struct buf **bp, uint8_t **data) > { > struct udf_mnt *udfmp; >- struct file_entry *fentry = NULL; > struct buf *bp1; > uint32_t max_size; > daddr_t sector; >@@ -1060,16 +1134,26 @@ udf_readatoffset(struct udf_node *node, int *size, off_t offset, > > udfmp = node->udfmp; > >- *bp = NULL; >+ /* >+ * This call is made not only to detect UDF_INVALID_BMAP case, >+ * max_size is used as an ad-hoc read-ahead hint for "normal" case. >+ */ > error = udf_bmap_internal(node, offset, §or, &max_size); > if (error == UDF_INVALID_BMAP) { > /* > * This error means that the file *data* is stored in the > * allocation descriptor field of the file entry. > */ >- fentry = node->fentry; >- *data = &fentry->data[le32toh(fentry->l_ea)]; >- *size = le32toh(fentry->l_ad); >+ if (node->fentry->tag.id == TAGID_FENTRY) { >+ struct file_entry *fentry = node->fentry; >+ *data = &fentry->data[le32toh(fentry->l_ea)]; >+ *size = le32toh(fentry->l_ad); >+ } >+ else { >+ struct extfile_entry *fentry = (struct extfile_entry *)node->fentry; >+ *data = &fentry->data[le32toh(fentry->l_ea)]; >+ *size = le32toh(fentry->l_ad); >+ } > return (0); > } else if (error != 0) { > return (error); >@@ -1078,9 +1162,10 @@ udf_readatoffset(struct udf_node *node, int *size, off_t offset, > /* Adjust the size so that it is within range */ > if (*size == 0 || *size > max_size) > *size = max_size; >- *size = min(*size, MAXBSIZE); >+ *size = min(*size, MAXBSIZE - blkoff(udfmp, offset)); > >- if ((error = udf_readlblks(udfmp, sector, *size + (offset & udfmp->bmask), bp))) { >+ *bp = NULL; >+ if ((error = bread(node->i_vnode, lblkno(udfmp, offset), (*size + blkoff(udfmp, offset) + udfmp->bmask) & ~udfmp->bmask, NOCRED, bp))) { > printf("warning: udf_readlblks returned error %d\n", error); > /* note: *bp may be non-NULL */ > return (error); >@@ -1137,12 +1222,12 @@ udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector, > do { > offset -= icblen; > ad_offset = sizeof(struct short_ad) * ad_num; >- if (ad_offset > le32toh(fentry->l_ad)) { >+ if (ad_offset > le32toh(GET_FENTRY_FIELD(fentry, l_ad))) { > printf("File offset out of bounds\n"); > return (EINVAL); > } > icb = GETICB(short_ad, fentry, >- le32toh(fentry->l_ea) + ad_offset); >+ le32toh(GET_FENTRY_FIELD(fentry, l_ea)) + ad_offset); > icblen = GETICBLEN(short_ad, icb); > ad_num++; > } while(offset >= icblen); >@@ -1162,12 +1247,12 @@ udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector, > do { > offset -= icblen; > ad_offset = sizeof(struct long_ad) * ad_num; >- if (ad_offset > le32toh(fentry->l_ad)) { >+ if (ad_offset > le32toh(GET_FENTRY_FIELD(fentry, l_ad))) { > printf("File offset out of bounds\n"); > return (EINVAL); > } > icb = GETICB(long_ad, fentry, >- le32toh(fentry->l_ea) + ad_offset); >+ le32toh(GET_FENTRY_FIELD(fentry, l_ea)) + ad_offset); > icblen = GETICBLEN(long_ad, icb); > ad_num++; > } while(offset >= icblen);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 120989
: 84915