1*5a0ec814Smiod /* $OpenBSD: udf_vnops.c,v 1.75 2024/10/18 05:52:32 miod Exp $ */ 2d9ac8608Spedro 3d9ac8608Spedro /* 4d9ac8608Spedro * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> 5d9ac8608Spedro * All rights reserved. 6d9ac8608Spedro * 7d9ac8608Spedro * Redistribution and use in source and binary forms, with or without 8d9ac8608Spedro * modification, are permitted provided that the following conditions 9d9ac8608Spedro * are met: 10d9ac8608Spedro * 1. Redistributions of source code must retain the above copyright 11d9ac8608Spedro * notice, this list of conditions and the following disclaimer. 12d9ac8608Spedro * 2. Redistributions in binary form must reproduce the above copyright 13d9ac8608Spedro * notice, this list of conditions and the following disclaimer in the 14d9ac8608Spedro * documentation and/or other materials provided with the distribution. 15d9ac8608Spedro * 16d9ac8608Spedro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17d9ac8608Spedro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18d9ac8608Spedro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19d9ac8608Spedro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20d9ac8608Spedro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21d9ac8608Spedro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22d9ac8608Spedro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23d9ac8608Spedro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24d9ac8608Spedro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25d9ac8608Spedro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26d9ac8608Spedro * SUCH DAMAGE. 27d9ac8608Spedro * 28d9ac8608Spedro * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.50 2005/01/28 14:42:16 phk Exp $ 29d9ac8608Spedro */ 30d9ac8608Spedro 31d9ac8608Spedro /* 32fcbf5195Sjmc * Ported to OpenBSD by Pedro Martelletto in February 2005. 33d9ac8608Spedro */ 34d9ac8608Spedro 35d9ac8608Spedro #include <sys/param.h> 36d9ac8608Spedro #include <sys/systm.h> 37d9ac8608Spedro #include <sys/namei.h> 38d9ac8608Spedro #include <sys/malloc.h> 39d9ac8608Spedro #include <sys/mutex.h> 40d9ac8608Spedro #include <sys/stat.h> 41d9ac8608Spedro #include <sys/buf.h> 42d9ac8608Spedro #include <sys/pool.h> 43d9ac8608Spedro #include <sys/lock.h> 44d9ac8608Spedro #include <sys/mount.h> 45d9ac8608Spedro #include <sys/vnode.h> 46d9ac8608Spedro #include <sys/dirent.h> 47d9ac8608Spedro #include <sys/queue.h> 48d9ac8608Spedro #include <sys/endian.h> 49544451c3Sderaadt #include <sys/specdev.h> 50782ebdf8Stedu #include <sys/unistd.h> 51d9ac8608Spedro 529dc9bb81Sdlg #include <crypto/siphash.h> 539dc9bb81Sdlg 54d9ac8608Spedro #include <isofs/udf/ecma167-udf.h> 55d9ac8608Spedro #include <isofs/udf/udf.h> 56d9ac8608Spedro #include <isofs/udf/udf_extern.h> 57d9ac8608Spedro 581abdbfdeSderaadt int udf_bmap_internal(struct unode *, off_t, daddr_t *, uint32_t *); 59d9ac8608Spedro 602d6b9e38Sclaudio const struct vops udf_vops = { 61dc81e71aSthib .vop_access = udf_access, 62dc81e71aSthib .vop_bmap = udf_bmap, 63dc81e71aSthib .vop_lookup = udf_lookup, 64dc81e71aSthib .vop_getattr = udf_getattr, 65dc81e71aSthib .vop_open = udf_open, 66dc81e71aSthib .vop_close = udf_close, 67dc81e71aSthib .vop_ioctl = udf_ioctl, 68dc81e71aSthib .vop_read = udf_read, 69dc81e71aSthib .vop_readdir = udf_readdir, 70dc81e71aSthib .vop_readlink = udf_readlink, 71dc81e71aSthib .vop_inactive = udf_inactive, 72dc81e71aSthib .vop_reclaim = udf_reclaim, 73dc81e71aSthib .vop_strategy = udf_strategy, 74dc81e71aSthib .vop_lock = udf_lock, 75dc81e71aSthib .vop_unlock = udf_unlock, 76bb394a57Sderaadt .vop_pathconf = udf_pathconf, 77dc81e71aSthib .vop_islocked = udf_islocked, 786e85720aSsemarie .vop_print = udf_print, 796e85720aSsemarie 806e85720aSsemarie .vop_abortop = NULL, 816e85720aSsemarie .vop_advlock = NULL, 826e85720aSsemarie .vop_bwrite = NULL, 836e85720aSsemarie .vop_create = NULL, 846e85720aSsemarie .vop_fsync = NULL, 856e85720aSsemarie .vop_link = NULL, 866e85720aSsemarie .vop_mknod = NULL, 87aa47c49aSsemarie .vop_remove = eopnotsupp, 886e85720aSsemarie .vop_rename = NULL, 896e85720aSsemarie .vop_revoke = NULL, 906e85720aSsemarie .vop_mkdir = NULL, 916e85720aSsemarie .vop_rmdir = NULL, 926e85720aSsemarie .vop_setattr = NULL, 936e85720aSsemarie .vop_symlink = NULL, 946e85720aSsemarie .vop_write = NULL, 956e85720aSsemarie .vop_kqfilter = NULL 96d9ac8608Spedro }; 97d9ac8608Spedro 98d9ac8608Spedro #define UDF_INVALID_BMAP -1 99d9ac8608Spedro 1000cad8b22Sguenther /* Look up a unode based on the udfino_t passed in and return its vnode */ 101d9ac8608Spedro int 1020cad8b22Sguenther udf_hashlookup(struct umount *ump, udfino_t id, int flags, struct vnode **vpp) 103d9ac8608Spedro { 1041af96cccSpedro struct unode *up; 105d9ac8608Spedro struct udf_hash_lh *lh; 106d9ac8608Spedro int error; 107d9ac8608Spedro 108d9ac8608Spedro *vpp = NULL; 109d9ac8608Spedro 110d9ac8608Spedro loop: 111170e22feSpedro mtx_enter(&ump->um_hashmtx); 1129dc9bb81Sdlg lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, &id, sizeof(id)) & 1139dc9bb81Sdlg ump->um_hashsz]; 114fc8d56caSpat if (lh == NULL) { 115170e22feSpedro mtx_leave(&ump->um_hashmtx); 116d9ac8608Spedro return (ENOENT); 117fc8d56caSpat } 118fc8d56caSpat 1191af96cccSpedro LIST_FOREACH(up, lh, u_le) { 1201af96cccSpedro if (up->u_ino == id) { 121170e22feSpedro mtx_leave(&ump->um_hashmtx); 12208107a0bSvisa error = vget(up->u_vnode, flags); 123d9ac8608Spedro if (error == ENOENT) 124d9ac8608Spedro goto loop; 125d9ac8608Spedro if (error) 126d9ac8608Spedro return (error); 1271af96cccSpedro *vpp = up->u_vnode; 128d9ac8608Spedro return (0); 129d9ac8608Spedro } 130d9ac8608Spedro } 131d9ac8608Spedro 132170e22feSpedro mtx_leave(&ump->um_hashmtx); 133d9ac8608Spedro 134d9ac8608Spedro return (0); 135d9ac8608Spedro } 136d9ac8608Spedro 137d9ac8608Spedro int 1381af96cccSpedro udf_hashins(struct unode *up) 139d9ac8608Spedro { 140170e22feSpedro struct umount *ump; 141d9ac8608Spedro struct udf_hash_lh *lh; 142d9ac8608Spedro 143170e22feSpedro ump = up->u_ump; 144d9ac8608Spedro 1456e880534Svisa vn_lock(up->u_vnode, LK_EXCLUSIVE | LK_RETRY); 146170e22feSpedro mtx_enter(&ump->um_hashmtx); 1479dc9bb81Sdlg lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, 1489dc9bb81Sdlg &up->u_ino, sizeof(up->u_ino)) & ump->um_hashsz]; 149d9ac8608Spedro if (lh == NULL) 15099b3a160Schl panic("hash entry is NULL, up->u_ino = %d", up->u_ino); 1511af96cccSpedro LIST_INSERT_HEAD(lh, up, u_le); 152170e22feSpedro mtx_leave(&ump->um_hashmtx); 153d9ac8608Spedro 154d9ac8608Spedro return (0); 155d9ac8608Spedro } 156d9ac8608Spedro 157d9ac8608Spedro int 1581af96cccSpedro udf_hashrem(struct unode *up) 159d9ac8608Spedro { 160170e22feSpedro struct umount *ump; 161d9ac8608Spedro struct udf_hash_lh *lh; 162d9ac8608Spedro 163170e22feSpedro ump = up->u_ump; 164d9ac8608Spedro 165170e22feSpedro mtx_enter(&ump->um_hashmtx); 1669dc9bb81Sdlg lh = &ump->um_hashtbl[SipHash24(&ump->um_hashkey, 1679dc9bb81Sdlg &up->u_ino, sizeof(up->u_ino)) & ump->um_hashsz]; 168d9ac8608Spedro if (lh == NULL) 1691af96cccSpedro panic("hash entry is NULL, up->u_ino = %d", up->u_ino); 1701af96cccSpedro LIST_REMOVE(up, u_le); 171170e22feSpedro mtx_leave(&ump->um_hashmtx); 172d9ac8608Spedro 173d9ac8608Spedro return (0); 174d9ac8608Spedro } 175d9ac8608Spedro 176d9ac8608Spedro int 177d9ac8608Spedro udf_allocv(struct mount *mp, struct vnode **vpp, struct proc *p) 178d9ac8608Spedro { 179d9ac8608Spedro int error; 180d9ac8608Spedro struct vnode *vp; 181d9ac8608Spedro 182dc81e71aSthib error = getnewvnode(VT_UDF, mp, &udf_vops, &vp); 183d9ac8608Spedro if (error) { 184d9ac8608Spedro printf("udf_allocv: failed to allocate new vnode\n"); 185d9ac8608Spedro return (error); 186d9ac8608Spedro } 187d9ac8608Spedro 188d9ac8608Spedro *vpp = vp; 189d9ac8608Spedro return (0); 190d9ac8608Spedro } 191d9ac8608Spedro 192d9ac8608Spedro /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */ 193d9ac8608Spedro static mode_t 1941af96cccSpedro udf_permtomode(struct unode *up) 195d9ac8608Spedro { 196d9ac8608Spedro uint32_t perm; 197d9ac8608Spedro uint16_t flags; 198d9ac8608Spedro mode_t mode; 199d9ac8608Spedro 2001af96cccSpedro perm = letoh32(up->u_fentry->perm); 2011af96cccSpedro flags = letoh16(up->u_fentry->icbtag.flags); 202d9ac8608Spedro 203d9ac8608Spedro mode = perm & UDF_FENTRY_PERM_USER_MASK; 204d9ac8608Spedro mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2); 205d9ac8608Spedro mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4); 206d9ac8608Spedro mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4); 207d9ac8608Spedro mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6); 208d9ac8608Spedro mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8); 209d9ac8608Spedro 210d9ac8608Spedro return (mode); 211d9ac8608Spedro } 212d9ac8608Spedro 213d9ac8608Spedro int 214d9ac8608Spedro udf_access(void *v) 215d9ac8608Spedro { 21699bc9d31Sderaadt struct vop_access_args *ap = v; 217d9ac8608Spedro struct vnode *vp; 2181af96cccSpedro struct unode *up; 219d9ac8608Spedro mode_t a_mode, mode; 220d9ac8608Spedro 221d9ac8608Spedro vp = ap->a_vp; 2221af96cccSpedro up = VTOU(vp); 223d9ac8608Spedro a_mode = ap->a_mode; 224d9ac8608Spedro 225d9ac8608Spedro if (a_mode & VWRITE) { 226d9ac8608Spedro switch (vp->v_type) { 227d9ac8608Spedro case VDIR: 228d9ac8608Spedro case VLNK: 229d9ac8608Spedro case VREG: 230d9ac8608Spedro return (EROFS); 231d9ac8608Spedro /* NOTREACHED */ 232d9ac8608Spedro default: 233d9ac8608Spedro break; 234d9ac8608Spedro } 235d9ac8608Spedro } 236d9ac8608Spedro 2371af96cccSpedro mode = udf_permtomode(up); 238d9ac8608Spedro 239141c07a8Smillert return (vaccess(vp->v_type, mode, up->u_fentry->uid, up->u_fentry->gid, 240141c07a8Smillert a_mode, ap->a_cred)); 241d9ac8608Spedro } 242d9ac8608Spedro 243d9ac8608Spedro static int mon_lens[2][12] = { 244d9ac8608Spedro {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 245d9ac8608Spedro {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 246d9ac8608Spedro }; 247d9ac8608Spedro 248d9ac8608Spedro static int 249d9ac8608Spedro udf_isaleapyear(int year) 250d9ac8608Spedro { 251d9ac8608Spedro int i; 252d9ac8608Spedro 253d9ac8608Spedro i = (year % 4) ? 0 : 1; 254d9ac8608Spedro i &= (year % 100) ? 1 : 0; 255d9ac8608Spedro i |= (year % 400) ? 0 : 1; 256d9ac8608Spedro 257d9ac8608Spedro return (i); 258d9ac8608Spedro } 259d9ac8608Spedro 260d9ac8608Spedro /* 261c184c659Spedro * This is just a rough hack. Daylight savings isn't calculated and tv_nsec 262d9ac8608Spedro * is ignored. 263d9ac8608Spedro * Timezone calculation compliments of Julian Elischer <julian@elischer.org>. 264d9ac8608Spedro */ 265d9ac8608Spedro static void 266d9ac8608Spedro udf_timetotimespec(struct timestamp *time, struct timespec *t) 267d9ac8608Spedro { 268d9ac8608Spedro int i, lpyear, daysinyear, year; 269d9ac8608Spedro union { 270d9ac8608Spedro uint16_t u_tz_offset; 271d9ac8608Spedro int16_t s_tz_offset; 272d9ac8608Spedro } tz; 273d9ac8608Spedro 274d9ac8608Spedro /* DirectCD seems to like using bogus year values */ 275d9ac8608Spedro year = letoh16(time->year); 276d9ac8608Spedro if (year < 1970) { 277d9ac8608Spedro t->tv_sec = 0; 278139ddf65Sguenther t->tv_nsec = 0; 279d9ac8608Spedro return; 280d9ac8608Spedro } 281d9ac8608Spedro 282d9ac8608Spedro /* Calculate the time and day */ 283139ddf65Sguenther t->tv_nsec = 1000 * time->usec + 100000 * time->hund_usec 284139ddf65Sguenther + 10000000 * time->centisec; 285d9ac8608Spedro t->tv_sec = time->second; 286d9ac8608Spedro t->tv_sec += time->minute * 60; 287d9ac8608Spedro t->tv_sec += time->hour * 3600; 288d9ac8608Spedro t->tv_sec += time->day * 3600 * 24; 289d9ac8608Spedro 2904a5c7b1eSpedro /* Calculate the month */ 291d9ac8608Spedro lpyear = udf_isaleapyear(year); 292d9ac8608Spedro for (i = 1; i < time->month; i++) 293d9ac8608Spedro t->tv_sec += mon_lens[lpyear][i] * 3600 * 24; 294d9ac8608Spedro 295d9ac8608Spedro /* Speed up the calculation */ 296d9ac8608Spedro if (year > 1979) 297d9ac8608Spedro t->tv_sec += 315532800; 298d9ac8608Spedro if (year > 1989) 299d9ac8608Spedro t->tv_sec += 315619200; 300d9ac8608Spedro if (year > 1999) 301d9ac8608Spedro t->tv_sec += 315532800; 302d9ac8608Spedro for (i = 2000; i < year; i++) { 303d9ac8608Spedro daysinyear = udf_isaleapyear(i) + 365 ; 304d9ac8608Spedro t->tv_sec += daysinyear * 3600 * 24; 305d9ac8608Spedro } 306d9ac8608Spedro 307d9ac8608Spedro /* 308d9ac8608Spedro * Calculate the time zone. The timezone is 12 bit signed 2's 309d9ac8608Spedro * compliment, so we gotta do some extra magic to handle it right. 310d9ac8608Spedro */ 311d9ac8608Spedro tz.u_tz_offset = letoh16(time->type_tz); 312d9ac8608Spedro tz.u_tz_offset &= 0x0fff; 313d9ac8608Spedro if (tz.u_tz_offset & 0x0800) 314d9ac8608Spedro tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */ 315d9ac8608Spedro if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047)) 316d9ac8608Spedro t->tv_sec -= tz.s_tz_offset * 60; 317d9ac8608Spedro 318d9ac8608Spedro return; 319d9ac8608Spedro } 320d9ac8608Spedro 321d9ac8608Spedro int 322d9ac8608Spedro udf_getattr(void *v) 323d9ac8608Spedro { 32499bc9d31Sderaadt struct vop_getattr_args *ap = v; 325d9ac8608Spedro struct vnode *vp; 3261af96cccSpedro struct unode *up; 327d9ac8608Spedro struct vattr *vap; 328b077103dSkrw struct extfile_entry *xfentry; 329d9ac8608Spedro struct file_entry *fentry; 330d9ac8608Spedro struct timespec ts; 331d9ac8608Spedro 332d9ac8608Spedro ts.tv_sec = 0; 333d9ac8608Spedro 334d9ac8608Spedro vp = ap->a_vp; 335d9ac8608Spedro vap = ap->a_vap; 3361af96cccSpedro up = VTOU(vp); 337b077103dSkrw 338b077103dSkrw xfentry = up->u_fentry; 339b077103dSkrw fentry = (struct file_entry *)up->u_fentry; 340d9ac8608Spedro 3411af96cccSpedro vap->va_fsid = up->u_dev; 3421af96cccSpedro vap->va_fileid = up->u_ino; 3431af96cccSpedro vap->va_mode = udf_permtomode(up); 344d9ac8608Spedro vap->va_nlink = letoh16(fentry->link_cnt); 345d9ac8608Spedro /* 346c184c659Spedro * The spec says that -1 is valid for uid/gid and indicates an 347d9ac8608Spedro * invalid uid/gid. How should this be represented? 348d9ac8608Spedro */ 349d9ac8608Spedro vap->va_uid = (letoh32(fentry->uid) == -1) ? 0 : letoh32(fentry->uid); 350d9ac8608Spedro vap->va_gid = (letoh32(fentry->gid) == -1) ? 0 : letoh32(fentry->gid); 351c184c659Spedro vap->va_rdev = 0; 352d9ac8608Spedro if (vp->v_type & VDIR) { 353337976e5Spedro vap->va_nlink++; /* Count a reference to ourselves */ 354d9ac8608Spedro /* 355d9ac8608Spedro * Directories that are recorded within their ICB will show 356d9ac8608Spedro * as having 0 blocks recorded. Since tradition dictates 357d9ac8608Spedro * that directories consume at least one logical block, 358d9ac8608Spedro * make it appear so. 359d9ac8608Spedro */ 360b077103dSkrw vap->va_size = up->u_ump->um_bsize; 361b077103dSkrw } else 362b077103dSkrw vap->va_size = letoh64(fentry->inf_len); 363b077103dSkrw if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { 364b077103dSkrw udf_timetotimespec(&xfentry->atime, &vap->va_atime); 365b077103dSkrw udf_timetotimespec(&xfentry->mtime, &vap->va_mtime); 366b077103dSkrw if ((vp->v_type & VDIR) && xfentry->logblks_rec != 0) 367b077103dSkrw vap->va_size = 368b077103dSkrw letoh64(xfentry->logblks_rec) * up->u_ump->um_bsize; 369b077103dSkrw } else { 370b077103dSkrw udf_timetotimespec(&fentry->atime, &vap->va_atime); 371b077103dSkrw udf_timetotimespec(&fentry->mtime, &vap->va_mtime); 372b077103dSkrw if ((vp->v_type & VDIR) && fentry->logblks_rec != 0) 373d9ac8608Spedro vap->va_size = 374884fd684Spedro letoh64(fentry->logblks_rec) * up->u_ump->um_bsize; 375d9ac8608Spedro } 376b077103dSkrw vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */ 377d9ac8608Spedro vap->va_flags = 0; 378d9ac8608Spedro vap->va_gen = 1; 379884fd684Spedro vap->va_blocksize = up->u_ump->um_bsize; 380d9ac8608Spedro vap->va_bytes = letoh64(fentry->inf_len); 381d9ac8608Spedro vap->va_type = vp->v_type; 382c184c659Spedro vap->va_filerev = 0; 383d9ac8608Spedro 384d9ac8608Spedro return (0); 385d9ac8608Spedro } 386d9ac8608Spedro 387d9ac8608Spedro int 388d9ac8608Spedro udf_open(void *v) 389d9ac8608Spedro { 390c184c659Spedro return (0); /* Nothing to be done at this point */ 391d9ac8608Spedro } 392d9ac8608Spedro 393d9ac8608Spedro int 394d9ac8608Spedro udf_close(void *v) 395d9ac8608Spedro { 396c184c659Spedro return (0); /* Nothing to be done at this point */ 397d9ac8608Spedro } 398d9ac8608Spedro 399d9ac8608Spedro /* 400d9ac8608Spedro * File specific ioctls. 401d9ac8608Spedro */ 402d9ac8608Spedro int 403d9ac8608Spedro udf_ioctl(void *v) 404d9ac8608Spedro { 405d9ac8608Spedro return (ENOTTY); 406d9ac8608Spedro } 407d9ac8608Spedro 408d9ac8608Spedro /* 409d9ac8608Spedro * I'm not sure that this has much value in a read-only filesystem, but 410d9ac8608Spedro * cd9660 has it too. 411d9ac8608Spedro */ 412bb394a57Sderaadt int 413bb394a57Sderaadt udf_pathconf(void *v) 414d9ac8608Spedro { 415bb394a57Sderaadt struct vop_pathconf_args *ap = v; 416a71fda8cSmatthew int error = 0; 417d9ac8608Spedro 418d9ac8608Spedro switch (ap->a_name) { 419d9ac8608Spedro case _PC_LINK_MAX: 420d9ac8608Spedro *ap->a_retval = 65535; 421a71fda8cSmatthew break; 422d9ac8608Spedro case _PC_NAME_MAX: 423d9ac8608Spedro *ap->a_retval = NAME_MAX; 424a71fda8cSmatthew break; 425bb394a57Sderaadt case _PC_CHOWN_RESTRICTED: 426bb394a57Sderaadt *ap->a_retval = 1; 427bb394a57Sderaadt break; 428d9ac8608Spedro case _PC_NO_TRUNC: 429d9ac8608Spedro *ap->a_retval = 1; 430a71fda8cSmatthew break; 431bb394a57Sderaadt case _PC_TIMESTAMP_RESOLUTION: 432bb394a57Sderaadt *ap->a_retval = 1000; /* 1 microsecond */ 433bb394a57Sderaadt break; 434d9ac8608Spedro default: 435a71fda8cSmatthew error = EINVAL; 436a71fda8cSmatthew break; 437d9ac8608Spedro } 438a71fda8cSmatthew 439a71fda8cSmatthew return (error); 440d9ac8608Spedro } 441d9ac8608Spedro 442d9ac8608Spedro int 443d9ac8608Spedro udf_read(void *v) 444d9ac8608Spedro { 44599bc9d31Sderaadt struct vop_read_args *ap = v; 446d9ac8608Spedro struct vnode *vp = ap->a_vp; 447d9ac8608Spedro struct uio *uio = ap->a_uio; 4481af96cccSpedro struct unode *up = VTOU(vp); 449d9ac8608Spedro struct buf *bp; 450d9ac8608Spedro uint8_t *data; 451d9ac8608Spedro off_t fsize, offset; 452d9ac8608Spedro int error = 0; 453d9ac8608Spedro int size; 454d9ac8608Spedro 455d9ac8608Spedro if (uio->uio_offset < 0) 456d9ac8608Spedro return (EINVAL); 457d9ac8608Spedro 4581af96cccSpedro fsize = letoh64(up->u_fentry->inf_len); 459d9ac8608Spedro 460d9ac8608Spedro while (uio->uio_offset < fsize && uio->uio_resid > 0) { 461d9ac8608Spedro offset = uio->uio_offset; 4625e04bb1bSstefan size = ulmin(uio->uio_resid, MAXBSIZE); 4635e04bb1bSstefan if (size > fsize - offset) 464d9ac8608Spedro size = fsize - offset; 4651af96cccSpedro error = udf_readatoffset(up, &size, offset, &bp, &data); 466d9ac8608Spedro if (error == 0) 4675e04bb1bSstefan error = uiomove(data, (size_t)size, uio); 468b077103dSkrw if (bp != NULL) { 469d9ac8608Spedro brelse(bp); 470b077103dSkrw bp = NULL; 471b077103dSkrw } 472d9ac8608Spedro if (error) 473d9ac8608Spedro break; 474479c151dSjsg } 475d9ac8608Spedro 476d9ac8608Spedro return (error); 477d9ac8608Spedro } 478d9ac8608Spedro 479d9ac8608Spedro /* 480b6647e39Smiod * Translate the name from a CS0 dstring to a 16-bit Unicode String. 481b6647e39Smiod * Hooks need to be placed in here to translate from Unicode to the encoding 482b6647e39Smiod * that the kernel/user expects. Return the length of the translated string. 483d9ac8608Spedro */ 4848885c958Spedro int 485170e22feSpedro udf_transname(char *cs0string, char *destname, int len, struct umount *ump) 486d9ac8608Spedro { 487d9ac8608Spedro unicode_t *transname; 488d9ac8608Spedro int i, unilen = 0, destlen; 489d9ac8608Spedro 4905bec07aaSpedro if (len > MAXNAMLEN) { 491b6647e39Smiod #ifdef DIAGNOSTIC 4925bec07aaSpedro printf("udf_transname(): name too long\n"); 493b6647e39Smiod #endif 4945bec07aaSpedro return (0); 4955bec07aaSpedro } 4965bec07aaSpedro 497d9ac8608Spedro /* allocate a buffer big enough to hold an 8->16 bit expansion */ 498d9ac8608Spedro transname = pool_get(&udf_trans_pool, PR_WAITOK); 499d9ac8608Spedro 500b6647e39Smiod if ((unilen = udf_rawnametounicode(len, cs0string, transname)) == -1) { 501b6647e39Smiod #ifdef DIAGNOSTIC 502b6647e39Smiod printf("udf_transname(): Unicode translation failed\n"); 503b6647e39Smiod #endif 504d9ac8608Spedro pool_put(&udf_trans_pool, transname); 505d9ac8608Spedro return (0); 506d9ac8608Spedro } 507d9ac8608Spedro 50860418546Spedro /* Pack it back to 8-bit Unicode. */ 509d9ac8608Spedro for (i = 0; i < unilen ; i++) 510d9ac8608Spedro if (transname[i] & 0xff00) 511b6647e39Smiod destname[i] = '?'; /* Fudge the 16bit chars */ 512d9ac8608Spedro else 513d9ac8608Spedro destname[i] = transname[i] & 0xff; 514d9ac8608Spedro 515d9ac8608Spedro pool_put(&udf_trans_pool, transname); 516b6647e39Smiod 517b6647e39Smiod /* Don't forget to terminate the string. */ 518d9ac8608Spedro destname[unilen] = 0; 519d9ac8608Spedro destlen = unilen; 520d9ac8608Spedro 521d9ac8608Spedro return (destlen); 522d9ac8608Spedro } 523d9ac8608Spedro 524d9ac8608Spedro /* 525d9ac8608Spedro * Compare a CS0 dstring with a name passed in from the VFS layer. Return 5264a5c7b1eSpedro * 0 on a successful match, nonzero otherwise. Unicode work may need to be 5274a5c7b1eSpedro * done here also. 528d9ac8608Spedro */ 529d9ac8608Spedro static int 530170e22feSpedro udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct umount *ump) 531d9ac8608Spedro { 532d9ac8608Spedro char *transname; 533d9ac8608Spedro int error = 0; 534d9ac8608Spedro 535c184c659Spedro /* This is overkill, but not worth creating a new pool */ 536d9ac8608Spedro transname = pool_get(&udf_trans_pool, PR_WAITOK); 537d9ac8608Spedro 538170e22feSpedro cs0len = udf_transname(cs0string, transname, cs0len, ump); 539d9ac8608Spedro 540d9ac8608Spedro /* Easy check. If they aren't the same length, they aren't equal */ 541d9ac8608Spedro if ((cs0len == 0) || (cs0len != cmplen)) 542d9ac8608Spedro error = -1; 543d9ac8608Spedro else 544d9ac8608Spedro error = bcmp(transname, cmpname, cmplen); 545d9ac8608Spedro 546d9ac8608Spedro pool_put(&udf_trans_pool, transname); 547d9ac8608Spedro 548d9ac8608Spedro return (error); 549d9ac8608Spedro } 550d9ac8608Spedro 551d9ac8608Spedro struct udf_uiodir { 552d9ac8608Spedro struct dirent *dirent; 553d9ac8608Spedro int eofflag; 554d9ac8608Spedro }; 555d9ac8608Spedro 556d9ac8608Spedro static int 55791a535ffSguenther udf_uiodir(struct udf_uiodir *uiodir, struct uio *uio, long off) 558d9ac8608Spedro { 5595e04bb1bSstefan size_t de_size = DIRENT_SIZE(uiodir->dirent); 560d9ac8608Spedro 561d9ac8608Spedro if (uio->uio_resid < de_size) { 562d9ac8608Spedro uiodir->eofflag = 0; 563d9ac8608Spedro return (-1); 564d9ac8608Spedro } 56591a535ffSguenther uiodir->dirent->d_off = off; 56691a535ffSguenther uiodir->dirent->d_reclen = de_size; 567d9ac8608Spedro 56846f7109aSclaudio if (memchr(uiodir->dirent->d_name, '/', 56946f7109aSclaudio uiodir->dirent->d_namlen) != NULL) { 57046f7109aSclaudio /* illegal file name */ 57146f7109aSclaudio return (EINVAL); 57246f7109aSclaudio } 57346f7109aSclaudio 5745e04bb1bSstefan return (uiomove(uiodir->dirent, de_size, uio)); 575d9ac8608Spedro } 576d9ac8608Spedro 577d9ac8608Spedro static struct udf_dirstream * 578170e22feSpedro udf_opendir(struct unode *up, int offset, int fsize, struct umount *ump) 579d9ac8608Spedro { 580d9ac8608Spedro struct udf_dirstream *ds; 581d9ac8608Spedro 582920b9ef6Smk ds = pool_get(&udf_ds_pool, PR_WAITOK | PR_ZERO); 583d9ac8608Spedro 5841af96cccSpedro ds->node = up; 585d9ac8608Spedro ds->offset = offset; 586170e22feSpedro ds->ump = ump; 587d9ac8608Spedro ds->fsize = fsize; 588d9ac8608Spedro 589d9ac8608Spedro return (ds); 590d9ac8608Spedro } 591d9ac8608Spedro 592d9ac8608Spedro static struct fileid_desc * 593d9ac8608Spedro udf_getfid(struct udf_dirstream *ds) 594d9ac8608Spedro { 595d9ac8608Spedro struct fileid_desc *fid; 596d9ac8608Spedro int error, frag_size = 0, total_fid_size; 597d9ac8608Spedro 598d9ac8608Spedro /* End of directory? */ 599d9ac8608Spedro if (ds->offset + ds->off >= ds->fsize) { 600d9ac8608Spedro ds->error = 0; 601d9ac8608Spedro return (NULL); 602d9ac8608Spedro } 603d9ac8608Spedro 604d9ac8608Spedro /* Grab the first extent of the directory */ 605d9ac8608Spedro if (ds->off == 0) { 606d9ac8608Spedro ds->size = 0; 607d9ac8608Spedro error = udf_readatoffset(ds->node, &ds->size, ds->offset, 608d9ac8608Spedro &ds->bp, &ds->data); 609d9ac8608Spedro if (error) { 610d9ac8608Spedro ds->error = error; 611b077103dSkrw if (ds->bp != NULL) { 612d9ac8608Spedro brelse(ds->bp); 613b077103dSkrw ds->bp = NULL; 614b077103dSkrw } 615d9ac8608Spedro return (NULL); 616d9ac8608Spedro } 617d9ac8608Spedro } 618d9ac8608Spedro 619d9ac8608Spedro /* 620d9ac8608Spedro * Clean up from a previous fragmented FID. 621c184c659Spedro * Is this the right place for this? 622d9ac8608Spedro */ 623d9ac8608Spedro if (ds->fid_fragment && ds->buf != NULL) { 624d9ac8608Spedro ds->fid_fragment = 0; 6250e5ae731Stedu free(ds->buf, M_UDFFID, 0); 626d9ac8608Spedro } 627d9ac8608Spedro 628d9ac8608Spedro fid = (struct fileid_desc*)&ds->data[ds->off]; 629d9ac8608Spedro 630d9ac8608Spedro /* 631d9ac8608Spedro * Check to see if the fid is fragmented. The first test 632d9ac8608Spedro * ensures that we don't wander off the end of the buffer 633d9ac8608Spedro * looking for the l_iu and l_fi fields. 634d9ac8608Spedro */ 635d9ac8608Spedro if (ds->off + UDF_FID_SIZE > ds->size || 636d9ac8608Spedro ds->off + letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){ 637d9ac8608Spedro 638d9ac8608Spedro /* Copy what we have of the fid into a buffer */ 639d9ac8608Spedro frag_size = ds->size - ds->off; 640170e22feSpedro if (frag_size >= ds->ump->um_bsize) { 641d9ac8608Spedro printf("udf: invalid FID fragment\n"); 642d9ac8608Spedro ds->error = EINVAL; 643d9ac8608Spedro return (NULL); 644d9ac8608Spedro } 645d9ac8608Spedro 646d9ac8608Spedro /* 647d9ac8608Spedro * File ID descriptors can only be at most one 648d9ac8608Spedro * logical sector in size. 649d9ac8608Spedro */ 650bc9397c2Skrw ds->buf = malloc(ds->ump->um_bsize, M_UDFFID, M_WAITOK|M_ZERO); 651d9ac8608Spedro bcopy(fid, ds->buf, frag_size); 652d9ac8608Spedro 653d9ac8608Spedro /* Reduce all of the casting magic */ 654d9ac8608Spedro fid = (struct fileid_desc*)ds->buf; 655d9ac8608Spedro 656b077103dSkrw if (ds->bp != NULL) { 657d9ac8608Spedro brelse(ds->bp); 658b077103dSkrw ds->bp = NULL; 659b077103dSkrw } 660d9ac8608Spedro 661d9ac8608Spedro /* Fetch the next allocation */ 662d9ac8608Spedro ds->offset += ds->size; 663d9ac8608Spedro ds->size = 0; 664d9ac8608Spedro error = udf_readatoffset(ds->node, &ds->size, ds->offset, 665d9ac8608Spedro &ds->bp, &ds->data); 666d9ac8608Spedro if (error) { 667d9ac8608Spedro ds->error = error; 668b077103dSkrw if (ds->bp != NULL) { 669b077103dSkrw brelse(ds->bp); 670b077103dSkrw ds->bp = NULL; 671b077103dSkrw } 672d9ac8608Spedro return (NULL); 673d9ac8608Spedro } 674d9ac8608Spedro 675d9ac8608Spedro /* 676d9ac8608Spedro * If the fragment was so small that we didn't get 677d9ac8608Spedro * the l_iu and l_fi fields, copy those in. 678d9ac8608Spedro */ 679d9ac8608Spedro if (frag_size < UDF_FID_SIZE) 680d9ac8608Spedro bcopy(ds->data, &ds->buf[frag_size], 681d9ac8608Spedro UDF_FID_SIZE - frag_size); 682d9ac8608Spedro 683d9ac8608Spedro /* 684d9ac8608Spedro * Now that we have enough of the fid to work with, 685d9ac8608Spedro * copy in the rest of the fid from the new 686d9ac8608Spedro * allocation. 687d9ac8608Spedro */ 688d9ac8608Spedro total_fid_size = UDF_FID_SIZE + letoh16(fid->l_iu) + fid->l_fi; 689170e22feSpedro if (total_fid_size > ds->ump->um_bsize) { 690d9ac8608Spedro printf("udf: invalid FID\n"); 691d9ac8608Spedro ds->error = EIO; 692d9ac8608Spedro return (NULL); 693d9ac8608Spedro } 694d9ac8608Spedro bcopy(ds->data, &ds->buf[frag_size], 695d9ac8608Spedro total_fid_size - frag_size); 696d9ac8608Spedro 697d9ac8608Spedro ds->fid_fragment = 1; 698d9ac8608Spedro } else { 699d9ac8608Spedro total_fid_size = letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE; 700d9ac8608Spedro } 701d9ac8608Spedro 702d9ac8608Spedro /* 703d9ac8608Spedro * Update the offset. Align on a 4 byte boundary because the 704d9ac8608Spedro * UDF spec says so. 705d9ac8608Spedro */ 706d9ac8608Spedro if (!ds->fid_fragment) { 707d9ac8608Spedro ds->off += (total_fid_size + 3) & ~0x03; 708d9ac8608Spedro } else { 709d9ac8608Spedro ds->off = (total_fid_size - frag_size + 3) & ~0x03; 710d9ac8608Spedro } 7116cb982a7Sguenther ds->this_off = ds->offset + ds->off; 712d9ac8608Spedro 713d9ac8608Spedro return (fid); 714d9ac8608Spedro } 715d9ac8608Spedro 716d9ac8608Spedro static void 717d9ac8608Spedro udf_closedir(struct udf_dirstream *ds) 718d9ac8608Spedro { 719d9ac8608Spedro 720b077103dSkrw if (ds->bp != NULL) { 721d9ac8608Spedro brelse(ds->bp); 722b077103dSkrw ds->bp = NULL; 723b077103dSkrw } 724d9ac8608Spedro 725d9ac8608Spedro if (ds->fid_fragment && ds->buf != NULL) 7260e5ae731Stedu free(ds->buf, M_UDFFID, 0); 727d9ac8608Spedro 728d9ac8608Spedro pool_put(&udf_ds_pool, ds); 729d9ac8608Spedro } 730d9ac8608Spedro 7316cb982a7Sguenther #define SELF_OFFSET 1 7326cb982a7Sguenther #define PARENT_OFFSET 2 7336cb982a7Sguenther 734d9ac8608Spedro int 735d9ac8608Spedro udf_readdir(void *v) 736d9ac8608Spedro { 73799bc9d31Sderaadt struct vop_readdir_args *ap = v; 738d9ac8608Spedro struct vnode *vp; 739d9ac8608Spedro struct uio *uio; 740d9ac8608Spedro struct dirent dir; 7411af96cccSpedro struct unode *up; 742170e22feSpedro struct umount *ump; 743d9ac8608Spedro struct fileid_desc *fid; 744d9ac8608Spedro struct udf_uiodir uiodir; 745d9ac8608Spedro struct udf_dirstream *ds; 74696c276e9Sguenther off_t last_off; 7476cb982a7Sguenther enum { MODE_NORMAL, MODE_SELF, MODE_PARENT } mode; 748d9ac8608Spedro int error = 0; 749d9ac8608Spedro 750d9ac8608Spedro vp = ap->a_vp; 751d9ac8608Spedro uio = ap->a_uio; 7521af96cccSpedro up = VTOU(vp); 753170e22feSpedro ump = up->u_ump; 754d9ac8608Spedro uiodir.eofflag = 1; 75591a535ffSguenther uiodir.dirent = &dir; 756ebee68f3Sguenther memset(&dir, 0, sizeof(dir)); 757d9ac8608Spedro 758d9ac8608Spedro /* 7596cb982a7Sguenther * if asked to start at SELF_OFFSET or PARENT_OFFSET, search 7606cb982a7Sguenther * for the parent ref 7616cb982a7Sguenther */ 7626cb982a7Sguenther if (uio->uio_offset == SELF_OFFSET) { 7636cb982a7Sguenther mode = MODE_SELF; 7646cb982a7Sguenther uio->uio_offset = 0; 7656cb982a7Sguenther } else if (uio->uio_offset == PARENT_OFFSET) { 7666cb982a7Sguenther mode = MODE_PARENT; 7676cb982a7Sguenther uio->uio_offset = 0; 7686cb982a7Sguenther } else 7696cb982a7Sguenther mode = MODE_NORMAL; 7706cb982a7Sguenther 7716cb982a7Sguenther /* 772d9ac8608Spedro * Iterate through the file id descriptors. Give the parent dir 773d9ac8608Spedro * entry special attention. 774d9ac8608Spedro */ 775b077103dSkrw if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 776b077103dSkrw up->u_ump->um_start += up->u_ump->um_meta_start; 777b077103dSkrw up->u_ump->um_len = up->u_ump->um_meta_len; 778b077103dSkrw } 7791af96cccSpedro ds = udf_opendir(up, uio->uio_offset, 7801af96cccSpedro letoh64(up->u_fentry->inf_len), up->u_ump); 781d9ac8608Spedro 78296c276e9Sguenther last_off = ds->offset + ds->off; 783d9ac8608Spedro while ((fid = udf_getfid(ds)) != NULL) { 784d9ac8608Spedro 785c184c659Spedro /* Should we return an error on a bad fid? */ 786d9ac8608Spedro if (udf_checktag(&fid->tag, TAGID_FID)) { 787b077103dSkrw printf("Invalid FID tag (%d)\n", fid->tag.id); 788d9ac8608Spedro error = EIO; 789d9ac8608Spedro break; 790d9ac8608Spedro } 791d9ac8608Spedro 792d9ac8608Spedro /* Is this a deleted file? */ 793d9ac8608Spedro if (fid->file_char & UDF_FILE_CHAR_DEL) 794d9ac8608Spedro continue; 795d9ac8608Spedro 796d9ac8608Spedro if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 797d9ac8608Spedro /* Do up the '.' and '..' entries. Dummy values are 79891a535ffSguenther * used for the offset since the offset here is 799d9ac8608Spedro * usually zero, and NFS doesn't like that value 800d9ac8608Spedro */ 8016cb982a7Sguenther if (mode == MODE_NORMAL) { 8021af96cccSpedro dir.d_fileno = up->u_ino; 803d9ac8608Spedro dir.d_type = DT_DIR; 804d9ac8608Spedro dir.d_name[0] = '.'; 805d9ac8608Spedro dir.d_name[1] = '\0'; 806d9ac8608Spedro dir.d_namlen = 1; 8076cb982a7Sguenther error = udf_uiodir(&uiodir, uio, SELF_OFFSET); 808d9ac8608Spedro if (error) 809d9ac8608Spedro break; 8106cb982a7Sguenther } 8116cb982a7Sguenther if (mode != MODE_PARENT) { 812d9ac8608Spedro dir.d_fileno = udf_getid(&fid->icb); 813d9ac8608Spedro dir.d_type = DT_DIR; 814d9ac8608Spedro dir.d_name[0] = '.'; 815d9ac8608Spedro dir.d_name[1] = '.'; 816d9ac8608Spedro dir.d_name[2] = '\0'; 817d9ac8608Spedro dir.d_namlen = 2; 8186cb982a7Sguenther error = udf_uiodir(&uiodir, uio, PARENT_OFFSET); 8196cb982a7Sguenther } 8206cb982a7Sguenther mode = MODE_NORMAL; 8216cb982a7Sguenther } else if (mode != MODE_NORMAL) { 8226cb982a7Sguenther continue; 823d9ac8608Spedro } else { 824d9ac8608Spedro dir.d_namlen = udf_transname(&fid->data[fid->l_iu], 825170e22feSpedro &dir.d_name[0], fid->l_fi, ump); 826d9ac8608Spedro dir.d_fileno = udf_getid(&fid->icb); 827d9ac8608Spedro dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ? 828d9ac8608Spedro DT_DIR : DT_UNKNOWN; 82991a535ffSguenther error = udf_uiodir(&uiodir, uio, ds->this_off); 830d9ac8608Spedro } 831d9ac8608Spedro if (error) { 83296c276e9Sguenther /* 83396c276e9Sguenther * udf_uiodir() indicates there isn't space for 83496c276e9Sguenther * another entry by returning -1 83596c276e9Sguenther */ 83696c276e9Sguenther if (error == -1) 83796c276e9Sguenther error = 0; 838d9ac8608Spedro break; 839d9ac8608Spedro } 84096c276e9Sguenther last_off = ds->this_off; 841d9ac8608Spedro } 842d9ac8608Spedro 843d9ac8608Spedro /* tell the calling layer whether we need to be called again */ 844d9ac8608Spedro *ap->a_eofflag = uiodir.eofflag; 84596c276e9Sguenther uio->uio_offset = last_off; 846d9ac8608Spedro 847d9ac8608Spedro if (!error) 848d9ac8608Spedro error = ds->error; 849d9ac8608Spedro 850d9ac8608Spedro udf_closedir(ds); 851b077103dSkrw if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 852b077103dSkrw up->u_ump->um_start = up->u_ump->um_realstart; 853b077103dSkrw up->u_ump->um_len = up->u_ump->um_reallen; 854b077103dSkrw } 855d9ac8608Spedro 856d9ac8608Spedro return (error); 857d9ac8608Spedro } 858d9ac8608Spedro 859d9ac8608Spedro /* Are there any implementations out there that do soft-links? */ 860d9ac8608Spedro int 861d9ac8608Spedro udf_readlink(void *v) 862d9ac8608Spedro { 863d9ac8608Spedro return (EOPNOTSUPP); 864d9ac8608Spedro } 865d9ac8608Spedro 866d9ac8608Spedro int 867d9ac8608Spedro udf_strategy(void *v) 868d9ac8608Spedro { 86999bc9d31Sderaadt struct vop_strategy_args *ap = v; 870d9ac8608Spedro struct buf *bp; 871d9ac8608Spedro struct vnode *vp; 8721af96cccSpedro struct unode *up; 873d9ac8608Spedro int maxsize, s, error; 874d9ac8608Spedro 875d9ac8608Spedro bp = ap->a_bp; 876d9ac8608Spedro vp = bp->b_vp; 8771af96cccSpedro up = VTOU(vp); 878d9ac8608Spedro 879d9ac8608Spedro /* cd9660 has this test reversed, but it seems more logical this way */ 880d9ac8608Spedro if (bp->b_blkno != bp->b_lblkno) { 881d9ac8608Spedro /* 882d9ac8608Spedro * Files that are embedded in the fentry don't translate well 883d9ac8608Spedro * to a block number. Reject. 884d9ac8608Spedro */ 885884fd684Spedro if (udf_bmap_internal(up, bp->b_lblkno * up->u_ump->um_bsize, 886d9ac8608Spedro &bp->b_lblkno, &maxsize)) { 887d9ac8608Spedro clrbuf(bp); 888d9ac8608Spedro bp->b_blkno = -1; 889d9ac8608Spedro } 890d9ac8608Spedro } else { 891d9ac8608Spedro error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 892d9ac8608Spedro if (error) { 893d9ac8608Spedro bp->b_error = error; 894d9ac8608Spedro bp->b_flags |= B_ERROR; 895d9ac8608Spedro s = splbio(); 896d9ac8608Spedro biodone(bp); 897d9ac8608Spedro splx(s); 898d9ac8608Spedro return (error); 899d9ac8608Spedro } 900d9ac8608Spedro 901d9ac8608Spedro if ((long)bp->b_blkno == -1) 902d9ac8608Spedro clrbuf(bp); 903d9ac8608Spedro } 904d9ac8608Spedro 905d9ac8608Spedro if ((long)bp->b_blkno == -1) { 906d9ac8608Spedro s = splbio(); 907d9ac8608Spedro biodone(bp); 908d9ac8608Spedro splx(s); 909d9ac8608Spedro } else { 910d9ac8608Spedro bp->b_dev = vp->v_rdev; 911f1993be3Svisa VOP_STRATEGY(up->u_devvp, bp); 912d9ac8608Spedro } 913d9ac8608Spedro 914d9ac8608Spedro return (0); 915d9ac8608Spedro } 916d9ac8608Spedro 917d9ac8608Spedro int 918d9ac8608Spedro udf_lock(void *v) 919d9ac8608Spedro { 92099bc9d31Sderaadt struct vop_lock_args *ap = v; 921d9ac8608Spedro struct vnode *vp = ap->a_vp; 922d9ac8608Spedro 92326b8ec94Snatano return rrw_enter(&VTOU(vp)->u_lock, ap->a_flags & LK_RWFLAGS); 924d9ac8608Spedro } 925d9ac8608Spedro 926d9ac8608Spedro int 927d9ac8608Spedro udf_unlock(void *v) 928d9ac8608Spedro { 92999bc9d31Sderaadt struct vop_unlock_args *ap = v; 930d9ac8608Spedro struct vnode *vp = ap->a_vp; 931d9ac8608Spedro 93226b8ec94Snatano rrw_exit(&VTOU(vp)->u_lock); 93326b8ec94Snatano return 0; 934d9ac8608Spedro } 935d9ac8608Spedro 936d9ac8608Spedro int 937d9ac8608Spedro udf_islocked(void *v) 938d9ac8608Spedro { 93999bc9d31Sderaadt struct vop_islocked_args *ap = v; 940d9ac8608Spedro 94126b8ec94Snatano return rrw_status(&VTOU(ap->a_vp)->u_lock); 942d9ac8608Spedro } 943d9ac8608Spedro 944d9ac8608Spedro int 945d9ac8608Spedro udf_print(void *v) 946d9ac8608Spedro { 947*5a0ec814Smiod #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG) 94899bc9d31Sderaadt struct vop_print_args *ap = v; 949d9ac8608Spedro struct vnode *vp = ap->a_vp; 9501af96cccSpedro struct unode *up = VTOU(vp); 951d9ac8608Spedro 952d9ac8608Spedro /* 953d9ac8608Spedro * Complete the information given by vprint(). 954d9ac8608Spedro */ 9551af96cccSpedro printf("tag VT_UDF, hash id %u\n", up->u_ino); 956f70ef8d5Sderaadt #ifdef DIAGNOSTIC 957d9ac8608Spedro printf("\n"); 958f70ef8d5Sderaadt #endif 959*5a0ec814Smiod #endif 960d9ac8608Spedro return (0); 961d9ac8608Spedro } 962d9ac8608Spedro 963d9ac8608Spedro int 964d9ac8608Spedro udf_bmap(void *v) 965d9ac8608Spedro { 96699bc9d31Sderaadt struct vop_bmap_args *ap = v; 9671af96cccSpedro struct unode *up; 968d9ac8608Spedro uint32_t max_size; 9691abdbfdeSderaadt daddr_t lsector; 970d9ac8608Spedro int error; 971d9ac8608Spedro 9721af96cccSpedro up = VTOU(ap->a_vp); 973d9ac8608Spedro 974d9ac8608Spedro if (ap->a_vpp != NULL) 9751af96cccSpedro *ap->a_vpp = up->u_devvp; 976d9ac8608Spedro if (ap->a_bnp == NULL) 977d9ac8608Spedro return (0); 978d9ac8608Spedro 979884fd684Spedro error = udf_bmap_internal(up, ap->a_bn * up->u_ump->um_bsize, 980797916ccSpedro &lsector, &max_size); 981d9ac8608Spedro if (error) 982d9ac8608Spedro return (error); 983d9ac8608Spedro 984d9ac8608Spedro /* Translate logical to physical sector number */ 985884fd684Spedro *ap->a_bnp = lsector << (up->u_ump->um_bshift - DEV_BSHIFT); 986d9ac8608Spedro 987d9ac8608Spedro /* Punt on read-ahead for now */ 988d9ac8608Spedro if (ap->a_runp) 989d9ac8608Spedro *ap->a_runp = 0; 990d9ac8608Spedro 991d9ac8608Spedro return (0); 992d9ac8608Spedro } 993d9ac8608Spedro 994d9ac8608Spedro /* 995d9ac8608Spedro * The all powerful VOP_LOOKUP(). 996d9ac8608Spedro */ 997d9ac8608Spedro int 998d9ac8608Spedro udf_lookup(void *v) 999d9ac8608Spedro { 100099bc9d31Sderaadt struct vop_lookup_args *ap = v; 1001d9ac8608Spedro struct vnode *dvp; 1002d9ac8608Spedro struct vnode *tdp = NULL; 1003d9ac8608Spedro struct vnode **vpp = ap->a_vpp; 10041af96cccSpedro struct unode *up; 1005170e22feSpedro struct umount *ump; 1006d9ac8608Spedro struct fileid_desc *fid = NULL; 1007d9ac8608Spedro struct udf_dirstream *ds; 1008d9ac8608Spedro struct proc *p; 1009d9ac8608Spedro u_long nameiop; 1010d9ac8608Spedro u_long flags; 1011d9ac8608Spedro char *nameptr; 1012d9ac8608Spedro long namelen; 10130cad8b22Sguenther udfino_t id = 0; 1014d9ac8608Spedro int offset, error = 0; 1015d9ac8608Spedro int numdirpasses, fsize; 1016d9ac8608Spedro 1017d9ac8608Spedro extern struct nchstats nchstats; 1018d9ac8608Spedro 1019d9ac8608Spedro dvp = ap->a_dvp; 10201af96cccSpedro up = VTOU(dvp); 1021170e22feSpedro ump = up->u_ump; 1022d9ac8608Spedro nameiop = ap->a_cnp->cn_nameiop; 1023d9ac8608Spedro flags = ap->a_cnp->cn_flags; 1024d9ac8608Spedro nameptr = ap->a_cnp->cn_nameptr; 1025d9ac8608Spedro namelen = ap->a_cnp->cn_namelen; 10261af96cccSpedro fsize = letoh64(up->u_fentry->inf_len); 1027d9ac8608Spedro p = ap->a_cnp->cn_proc; 102869d99b4dSpedro *vpp = NULL; 1029d9ac8608Spedro 1030d9ac8608Spedro /* 1031d9ac8608Spedro * Make sure the process can scan the requested directory. 1032d9ac8608Spedro */ 1033d9ac8608Spedro error = VOP_ACCESS(dvp, VEXEC, ap->a_cnp->cn_cred, p); 1034d9ac8608Spedro if (error) 1035d9ac8608Spedro return (error); 1036d9ac8608Spedro 1037d9ac8608Spedro /* 1038d9ac8608Spedro * Check if the (directory, name) tuple has been already cached. 1039d9ac8608Spedro */ 1040d9ac8608Spedro error = cache_lookup(dvp, vpp, ap->a_cnp); 1041d9ac8608Spedro if (error >= 0) 1042d9ac8608Spedro return (error); 1043d9ac8608Spedro else 1044d9ac8608Spedro error = 0; 1045d9ac8608Spedro 1046d9ac8608Spedro /* 1047d9ac8608Spedro * If dvp is what's being looked up, then return it. 1048d9ac8608Spedro */ 1049d9ac8608Spedro if (ap->a_cnp->cn_namelen == 1 && ap->a_cnp->cn_nameptr[0] == '.') { 1050627b2c48Sthib vref(dvp); 1051d9ac8608Spedro *vpp = dvp; 1052d9ac8608Spedro return (0); 1053d9ac8608Spedro } 1054d9ac8608Spedro 1055d9ac8608Spedro /* 1056d9ac8608Spedro * If this is a LOOKUP and we've already partially searched through 1057d9ac8608Spedro * the directory, pick up where we left off and flag that the 1058d9ac8608Spedro * directory may need to be searched twice. For a full description, 1059d9ac8608Spedro * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup() 1060d9ac8608Spedro */ 10611af96cccSpedro if (nameiop != LOOKUP || up->u_diroff == 0 || up->u_diroff > fsize) { 1062d9ac8608Spedro offset = 0; 1063d9ac8608Spedro numdirpasses = 1; 1064d9ac8608Spedro } else { 10651af96cccSpedro offset = up->u_diroff; 1066d9ac8608Spedro numdirpasses = 2; 1067d9ac8608Spedro nchstats.ncs_2passes++; 1068d9ac8608Spedro } 1069d9ac8608Spedro 1070b077103dSkrw if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1071b077103dSkrw up->u_ump->um_start += up->u_ump->um_meta_start; 1072b077103dSkrw up->u_ump->um_len = up->u_ump->um_meta_len; 1073b077103dSkrw } 1074d9ac8608Spedro lookloop: 1075170e22feSpedro ds = udf_opendir(up, offset, fsize, ump); 1076d9ac8608Spedro 1077d9ac8608Spedro while ((fid = udf_getfid(ds)) != NULL) { 1078d9ac8608Spedro /* Check for a valid FID tag. */ 1079d9ac8608Spedro if (udf_checktag(&fid->tag, TAGID_FID)) { 1080d9ac8608Spedro printf("udf_lookup: Invalid tag\n"); 1081d9ac8608Spedro error = EIO; 1082d9ac8608Spedro break; 1083d9ac8608Spedro } 1084d9ac8608Spedro 1085d9ac8608Spedro /* Is this a deleted file? */ 1086d9ac8608Spedro if (fid->file_char & UDF_FILE_CHAR_DEL) 1087d9ac8608Spedro continue; 1088d9ac8608Spedro 1089d9ac8608Spedro if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 1090d9ac8608Spedro if (flags & ISDOTDOT) { 1091d9ac8608Spedro id = udf_getid(&fid->icb); 1092d9ac8608Spedro break; 1093d9ac8608Spedro } 1094d9ac8608Spedro } else { 1095d9ac8608Spedro if (!(udf_cmpname(&fid->data[fid->l_iu], 1096170e22feSpedro nameptr, fid->l_fi, namelen, ump))) { 1097d9ac8608Spedro id = udf_getid(&fid->icb); 1098d9ac8608Spedro break; 1099d9ac8608Spedro } 1100d9ac8608Spedro } 1101d9ac8608Spedro } 1102d9ac8608Spedro 1103d9ac8608Spedro if (!error) 1104d9ac8608Spedro error = ds->error; 1105d9ac8608Spedro 1106d9ac8608Spedro if (error) { 1107d9ac8608Spedro udf_closedir(ds); 1108b077103dSkrw if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1109b077103dSkrw up->u_ump->um_start = up->u_ump->um_realstart; 1110b077103dSkrw up->u_ump->um_len = up->u_ump->um_reallen; 1111b077103dSkrw } 1112d9ac8608Spedro return (error); 1113d9ac8608Spedro } 1114d9ac8608Spedro 1115d9ac8608Spedro /* Did we have a match? */ 1116d9ac8608Spedro if (id) { 1117170e22feSpedro error = udf_vget(ump->um_mountp, id, &tdp); 1118d9ac8608Spedro if (!error) { 1119d9ac8608Spedro /* 1120d9ac8608Spedro * Remember where this entry was if it's the final 1121d9ac8608Spedro * component. 1122d9ac8608Spedro */ 1123d9ac8608Spedro if ((flags & ISLASTCN) && nameiop == LOOKUP) 11241af96cccSpedro up->u_diroff = ds->offset + ds->off; 1125d9ac8608Spedro if (numdirpasses == 2) 1126d9ac8608Spedro nchstats.ncs_pass2++; 1127d9ac8608Spedro if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 1128d9ac8608Spedro ap->a_cnp->cn_flags |= PDIRUNLOCK; 112936bb23f1Svisa VOP_UNLOCK(dvp); 1130d9ac8608Spedro } 1131d9ac8608Spedro 1132d9ac8608Spedro *vpp = tdp; 1133d9ac8608Spedro } 1134d9ac8608Spedro } else { 1135d9ac8608Spedro /* Name wasn't found on this pass. Do another pass? */ 1136d9ac8608Spedro if (numdirpasses == 2) { 1137d9ac8608Spedro numdirpasses--; 1138d9ac8608Spedro offset = 0; 1139d9ac8608Spedro udf_closedir(ds); 1140d9ac8608Spedro goto lookloop; 1141d9ac8608Spedro } 1142d9ac8608Spedro 1143d9ac8608Spedro if ((flags & ISLASTCN) && 1144d9ac8608Spedro (nameiop == CREATE || nameiop == RENAME)) { 1145d9ac8608Spedro error = EROFS; 1146d9ac8608Spedro } else { 1147d9ac8608Spedro error = ENOENT; 1148d9ac8608Spedro } 1149d9ac8608Spedro } 1150d9ac8608Spedro 1151d9ac8608Spedro /* 1152d9ac8608Spedro * Cache the result of this lookup. 1153d9ac8608Spedro */ 1154d9ac8608Spedro if (flags & MAKEENTRY) 1155d9ac8608Spedro cache_enter(dvp, *vpp, ap->a_cnp); 1156d9ac8608Spedro 1157d9ac8608Spedro udf_closedir(ds); 1158b077103dSkrw if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) { 1159b077103dSkrw up->u_ump->um_start = up->u_ump->um_realstart; 1160b077103dSkrw up->u_ump->um_len = up->u_ump->um_reallen; 1161b077103dSkrw } 1162d9ac8608Spedro 1163d9ac8608Spedro return (error); 1164d9ac8608Spedro } 1165d9ac8608Spedro 1166d9ac8608Spedro int 1167d9ac8608Spedro udf_inactive(void *v) 1168d9ac8608Spedro { 116999bc9d31Sderaadt struct vop_inactive_args *ap = v; 1170d9ac8608Spedro struct vnode *vp = ap->a_vp; 1171d9ac8608Spedro 1172d9ac8608Spedro /* 1173d9ac8608Spedro * No need to sync anything, so just unlock the vnode and return. 1174d9ac8608Spedro */ 117536bb23f1Svisa VOP_UNLOCK(vp); 1176d9ac8608Spedro 1177d9ac8608Spedro return (0); 1178d9ac8608Spedro } 1179d9ac8608Spedro 1180d9ac8608Spedro int 1181d9ac8608Spedro udf_reclaim(void *v) 1182d9ac8608Spedro { 118399bc9d31Sderaadt struct vop_reclaim_args *ap = v; 1184d9ac8608Spedro struct vnode *vp; 11851af96cccSpedro struct unode *up; 1186d9ac8608Spedro 1187d9ac8608Spedro vp = ap->a_vp; 11881af96cccSpedro up = VTOU(vp); 1189d9ac8608Spedro 11901af96cccSpedro if (up != NULL) { 11911af96cccSpedro udf_hashrem(up); 11921af96cccSpedro if (up->u_devvp) { 11931af96cccSpedro vrele(up->u_devvp); 11941af96cccSpedro up->u_devvp = 0; 1195d9ac8608Spedro } 1196d9ac8608Spedro 11971af96cccSpedro if (up->u_fentry != NULL) 11980e5ae731Stedu free(up->u_fentry, M_UDFFENTRY, 0); 11995921d099Spedro 12001af96cccSpedro pool_put(&unode_pool, up); 1201d9ac8608Spedro vp->v_data = NULL; 1202d9ac8608Spedro } 1203d9ac8608Spedro 1204d9ac8608Spedro return (0); 1205d9ac8608Spedro } 1206d9ac8608Spedro 1207d9ac8608Spedro /* 1208d9ac8608Spedro * Read the block and then set the data pointer to correspond with the 1209d9ac8608Spedro * offset passed in. Only read in at most 'size' bytes, and then set 'size' 1210d9ac8608Spedro * to the number of bytes pointed to. If 'size' is zero, try to read in a 1211d9ac8608Spedro * whole extent. 1212d9ac8608Spedro * 1213d9ac8608Spedro * Note that *bp may be assigned error or not. 1214d9ac8608Spedro * 1215d9ac8608Spedro */ 1216d9ac8608Spedro int 12171af96cccSpedro udf_readatoffset(struct unode *up, int *size, off_t offset, 1218d9ac8608Spedro struct buf **bp, uint8_t **data) 1219d9ac8608Spedro { 1220170e22feSpedro struct umount *ump; 1221b077103dSkrw struct extfile_entry *xfentry = NULL; 1222d9ac8608Spedro struct file_entry *fentry = NULL; 1223d9ac8608Spedro struct buf *bp1; 1224d9ac8608Spedro uint32_t max_size; 12251abdbfdeSderaadt daddr_t sector; 1226d9ac8608Spedro int error; 1227d9ac8608Spedro 1228170e22feSpedro ump = up->u_ump; 1229d9ac8608Spedro 1230d9ac8608Spedro *bp = NULL; 12311af96cccSpedro error = udf_bmap_internal(up, offset, §or, &max_size); 1232d9ac8608Spedro if (error == UDF_INVALID_BMAP) { 1233d9ac8608Spedro /* 1234d9ac8608Spedro * This error means that the file *data* is stored in the 1235d9ac8608Spedro * allocation descriptor field of the file entry. 1236d9ac8608Spedro */ 1237b077103dSkrw if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) { 1238b077103dSkrw xfentry = up->u_fentry; 1239b077103dSkrw *data = &xfentry->data[letoh32(xfentry->l_ea)]; 1240b077103dSkrw *size = letoh32(xfentry->l_ad); 1241b077103dSkrw } else { 1242b077103dSkrw fentry = (struct file_entry *)up->u_fentry; 1243d9ac8608Spedro *data = &fentry->data[letoh32(fentry->l_ea)]; 1244d9ac8608Spedro *size = letoh32(fentry->l_ad); 1245b077103dSkrw } 1246d9ac8608Spedro return (0); 1247d9ac8608Spedro } else if (error != 0) { 1248d9ac8608Spedro return (error); 1249d9ac8608Spedro } 1250d9ac8608Spedro 1251d9ac8608Spedro /* Adjust the size so that it is within range */ 1252d9ac8608Spedro if (*size == 0 || *size > max_size) 1253d9ac8608Spedro *size = max_size; 1254d9ac8608Spedro *size = min(*size, MAXBSIZE); 1255d9ac8608Spedro 1256170e22feSpedro if ((error = udf_readlblks(ump, sector, *size, bp))) { 1257d9ac8608Spedro printf("warning: udf_readlblks returned error %d\n", error); 1258d9ac8608Spedro /* note: *bp may be non-NULL */ 1259d9ac8608Spedro return (error); 1260d9ac8608Spedro } 1261d9ac8608Spedro 1262d9ac8608Spedro bp1 = *bp; 1263170e22feSpedro *data = (uint8_t *)&bp1->b_data[offset % ump->um_bsize]; 1264d9ac8608Spedro return (0); 1265d9ac8608Spedro } 1266d9ac8608Spedro 1267d9ac8608Spedro /* 1268d9ac8608Spedro * Translate a file offset into a logical block and then into a physical 1269d9ac8608Spedro * block. 1270d9ac8608Spedro */ 1271d9ac8608Spedro int 12721abdbfdeSderaadt udf_bmap_internal(struct unode *up, off_t offset, daddr_t *sector, 1273d9ac8608Spedro uint32_t *max_size) 1274d9ac8608Spedro { 1275170e22feSpedro struct umount *ump; 1276b077103dSkrw struct extfile_entry *xfentry; 1277d9ac8608Spedro struct file_entry *fentry; 1278d9ac8608Spedro void *icb; 1279d9ac8608Spedro struct icb_tag *tag; 1280d9ac8608Spedro uint32_t icblen = 0; 12811abdbfdeSderaadt daddr_t lsector; 1282d9ac8608Spedro int ad_offset, ad_num = 0; 1283b077103dSkrw int i, p_offset, l_ea, l_ad; 1284d9ac8608Spedro 1285170e22feSpedro ump = up->u_ump; 1286b077103dSkrw xfentry = up->u_fentry; 1287b077103dSkrw fentry = (struct file_entry *)up->u_fentry; 1288d9ac8608Spedro tag = &fentry->icbtag; 1289b077103dSkrw if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) { 1290b077103dSkrw l_ea = letoh32(xfentry->l_ea); 1291b077103dSkrw l_ad = letoh32(xfentry->l_ad); 1292b077103dSkrw } else { 1293b077103dSkrw l_ea = letoh32(fentry->l_ea); 1294b077103dSkrw l_ad = letoh32(fentry->l_ad); 1295b077103dSkrw } 1296d9ac8608Spedro 1297d9ac8608Spedro switch (letoh16(tag->strat_type)) { 1298d9ac8608Spedro case 4: 1299d9ac8608Spedro break; 1300d9ac8608Spedro 1301d9ac8608Spedro case 4096: 1302d9ac8608Spedro printf("Cannot deal with strategy4096 yet!\n"); 1303d9ac8608Spedro return (ENODEV); 1304d9ac8608Spedro 1305d9ac8608Spedro default: 1306d9ac8608Spedro printf("Unknown strategy type %d\n", tag->strat_type); 1307d9ac8608Spedro return (ENODEV); 1308d9ac8608Spedro } 1309d9ac8608Spedro 1310d9ac8608Spedro switch (letoh16(tag->flags) & 0x7) { 1311d9ac8608Spedro case 0: 1312d9ac8608Spedro /* 1313d9ac8608Spedro * The allocation descriptor field is filled with short_ad's. 1314d9ac8608Spedro * If the offset is beyond the current extent, look for the 1315d9ac8608Spedro * next extent. 1316d9ac8608Spedro */ 1317d9ac8608Spedro do { 1318d9ac8608Spedro offset -= icblen; 1319d9ac8608Spedro ad_offset = sizeof(struct short_ad) * ad_num; 1320b077103dSkrw if (ad_offset > l_ad) { 1321b077103dSkrw printf("SFile offset out of bounds (%d > %d)\n", 1322b077103dSkrw ad_offset, l_ad); 1323d9ac8608Spedro return (EINVAL); 1324d9ac8608Spedro } 1325b077103dSkrw 1326b077103dSkrw if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) 1327b077103dSkrw icb = GETICB(short_ad, xfentry, l_ea + ad_offset); 1328b077103dSkrw else 1329b077103dSkrw icb = GETICB(short_ad, fentry, l_ea + ad_offset); 1330b077103dSkrw 1331d9ac8608Spedro icblen = GETICBLEN(short_ad, icb); 1332d9ac8608Spedro ad_num++; 1333d9ac8608Spedro } while(offset >= icblen); 1334d9ac8608Spedro 1335170e22feSpedro lsector = (offset >> ump->um_bshift) + 1336de3bd4b9Skrw letoh32(((struct short_ad *)(icb))->lb_num); 1337d9ac8608Spedro 1338d9ac8608Spedro *max_size = GETICBLEN(short_ad, icb); 1339d9ac8608Spedro 1340d9ac8608Spedro break; 1341d9ac8608Spedro case 1: 1342d9ac8608Spedro /* 1343d9ac8608Spedro * The allocation descriptor field is filled with long_ad's 1344d9ac8608Spedro * If the offset is beyond the current extent, look for the 1345d9ac8608Spedro * next extent. 1346d9ac8608Spedro */ 1347d9ac8608Spedro do { 1348d9ac8608Spedro offset -= icblen; 1349d9ac8608Spedro ad_offset = sizeof(struct long_ad) * ad_num; 1350b077103dSkrw if (ad_offset > l_ad) { 1351b077103dSkrw printf("LFile offset out of bounds (%d > %d)\n", 1352b077103dSkrw ad_offset, l_ad); 1353d9ac8608Spedro return (EINVAL); 1354d9ac8608Spedro } 1355b077103dSkrw if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) 1356b077103dSkrw icb = GETICB(long_ad, xfentry, l_ea + ad_offset); 1357b077103dSkrw else 1358b077103dSkrw icb = GETICB(long_ad, fentry, l_ea + ad_offset); 1359d9ac8608Spedro icblen = GETICBLEN(long_ad, icb); 1360d9ac8608Spedro ad_num++; 1361d9ac8608Spedro } while(offset >= icblen); 1362d9ac8608Spedro 1363170e22feSpedro lsector = (offset >> ump->um_bshift) + 1364d9ac8608Spedro letoh32(((struct long_ad *)(icb))->loc.lb_num); 1365d9ac8608Spedro 1366d9ac8608Spedro *max_size = GETICBLEN(long_ad, icb); 1367d9ac8608Spedro 1368d9ac8608Spedro break; 1369d9ac8608Spedro case 3: 1370d9ac8608Spedro /* 1371d9ac8608Spedro * This type means that the file *data* is stored in the 1372d9ac8608Spedro * allocation descriptor field of the file entry. 1373d9ac8608Spedro */ 1374d9ac8608Spedro *max_size = 0; 1375170e22feSpedro *sector = up->u_ino + ump->um_start; 1376d9ac8608Spedro 1377d9ac8608Spedro return (UDF_INVALID_BMAP); 1378d9ac8608Spedro case 2: 1379d9ac8608Spedro /* DirectCD does not use extended_ad's */ 1380d9ac8608Spedro default: 1381d9ac8608Spedro printf("Unsupported allocation descriptor %d\n", 1382d9ac8608Spedro tag->flags & 0x7); 1383d9ac8608Spedro return (ENODEV); 1384d9ac8608Spedro } 1385d9ac8608Spedro 1386170e22feSpedro *sector = lsector + ump->um_start; 1387d9ac8608Spedro 1388d9ac8608Spedro /* 1389d9ac8608Spedro * Check the sparing table. Each entry represents the beginning of 1390d9ac8608Spedro * a packet. 1391d9ac8608Spedro */ 1392170e22feSpedro if (ump->um_stbl != NULL) { 1393170e22feSpedro for (i = 0; i< ump->um_stbl_len; i++) { 1394d9ac8608Spedro p_offset = 1395170e22feSpedro lsector - letoh32(ump->um_stbl->entries[i].org); 1396170e22feSpedro if ((p_offset < ump->um_psecs) && (p_offset >= 0)) { 1397d9ac8608Spedro *sector = 1398170e22feSpedro letoh32(ump->um_stbl->entries[i].map) + 1399d9ac8608Spedro p_offset; 1400d9ac8608Spedro break; 1401d9ac8608Spedro } 1402d9ac8608Spedro } 1403d9ac8608Spedro } 1404d9ac8608Spedro 1405d9ac8608Spedro return (0); 1406d9ac8608Spedro } 1407