194663Sscottl/*- 294663Sscottl * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> 394663Sscottl * All rights reserved. 494663Sscottl * 594663Sscottl * Redistribution and use in source and binary forms, with or without 694663Sscottl * modification, are permitted provided that the following conditions 794663Sscottl * are met: 894663Sscottl * 1. Redistributions of source code must retain the above copyright 994663Sscottl * notice, this list of conditions and the following disclaimer. 1094663Sscottl * 2. Redistributions in binary form must reproduce the above copyright 1194663Sscottl * notice, this list of conditions and the following disclaimer in the 1294663Sscottl * documentation and/or other materials provided with the distribution. 1394663Sscottl * 1494663Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1594663Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1694663Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1794663Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1894663Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1994663Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2094663Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2194663Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2294663Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2394663Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2494663Sscottl * SUCH DAMAGE. 2594663Sscottl * 2694663Sscottl * $FreeBSD$ 2794663Sscottl */ 2894663Sscottl 2994663Sscottl/* udf_vnops.c */ 3094663Sscottl/* Take care of the vnode side of things */ 3194663Sscottl 3294663Sscottl#include <sys/param.h> 3394663Sscottl#include <sys/systm.h> 3494663Sscottl#include <sys/namei.h> 3594663Sscottl#include <sys/kernel.h> 3694663Sscottl#include <sys/malloc.h> 3794663Sscottl#include <sys/stat.h> 3894663Sscottl#include <sys/bio.h> 39143571Sphk#include <sys/conf.h> 4094663Sscottl#include <sys/buf.h> 41122102Sscottl#include <sys/iconv.h> 4294663Sscottl#include <sys/mount.h> 4394663Sscottl#include <sys/vnode.h> 4494663Sscottl#include <sys/dirent.h> 4594663Sscottl#include <sys/queue.h> 4694663Sscottl#include <sys/unistd.h> 47130986Sscottl#include <sys/endian.h> 4894663Sscottl 4994663Sscottl#include <vm/uma.h> 5094663Sscottl 5194663Sscottl#include <fs/udf/ecma167-udf.h> 5294663Sscottl#include <fs/udf/osta.h> 5394663Sscottl#include <fs/udf/udf.h> 54122102Sscottl#include <fs/udf/udf_mount.h> 5594663Sscottl 56122102Sscottlextern struct iconv_functions *udf_iconv; 57122102Sscottl 58138270Sphkstatic vop_access_t udf_access; 59138270Sphkstatic vop_getattr_t udf_getattr; 60165500Spavstatic vop_open_t udf_open; 61138270Sphkstatic vop_ioctl_t udf_ioctl; 62138270Sphkstatic vop_pathconf_t udf_pathconf; 63188245Sjhbstatic vop_print_t udf_print; 64138270Sphkstatic vop_read_t udf_read; 65138270Sphkstatic vop_readdir_t udf_readdir; 66138270Sphkstatic vop_readlink_t udf_readlink; 67188245Sjhbstatic vop_setattr_t udf_setattr; 68138270Sphkstatic vop_strategy_t udf_strategy; 69138270Sphkstatic vop_bmap_t udf_bmap; 70138270Sphkstatic vop_cachedlookup_t udf_lookup; 71138270Sphkstatic vop_reclaim_t udf_reclaim; 72166774Spjdstatic vop_vptofh_t udf_vptofh; 73140105Sscottlstatic int udf_readatoffset(struct udf_node *node, int *size, off_t offset, 74140105Sscottl struct buf **bp, uint8_t **data); 75140105Sscottlstatic int udf_bmap_internal(struct udf_node *node, off_t offset, 76140105Sscottl daddr_t *sector, uint32_t *max_size); 7794663Sscottl 78138290Sphkstatic struct vop_vector udf_vnodeops = { 79138290Sphk .vop_default = &default_vnodeops, 80140196Sphk 81138290Sphk .vop_access = udf_access, 82138290Sphk .vop_bmap = udf_bmap, 83138290Sphk .vop_cachedlookup = udf_lookup, 84138290Sphk .vop_getattr = udf_getattr, 85138290Sphk .vop_ioctl = udf_ioctl, 86138290Sphk .vop_lookup = vfs_cache_lookup, 87165500Spav .vop_open = udf_open, 88138290Sphk .vop_pathconf = udf_pathconf, 89188245Sjhb .vop_print = udf_print, 90138290Sphk .vop_read = udf_read, 91138290Sphk .vop_readdir = udf_readdir, 92138290Sphk .vop_readlink = udf_readlink, 93138290Sphk .vop_reclaim = udf_reclaim, 94188245Sjhb .vop_setattr = udf_setattr, 95138290Sphk .vop_strategy = udf_strategy, 96166774Spjd .vop_vptofh = udf_vptofh, 9794663Sscottl}; 9894663Sscottl 99188245Sjhbstruct vop_vector udf_fifoops = { 100188245Sjhb .vop_default = &fifo_specops, 101188245Sjhb .vop_access = udf_access, 102188245Sjhb .vop_getattr = udf_getattr, 103188245Sjhb .vop_print = udf_print, 104188245Sjhb .vop_reclaim = udf_reclaim, 105188245Sjhb .vop_setattr = udf_setattr, 106188245Sjhb .vop_vptofh = udf_vptofh, 107188245Sjhb}; 108188245Sjhb 109227293Sedstatic MALLOC_DEFINE(M_UDFFID, "udf_fid", "UDF FileId structure"); 110227293Sedstatic MALLOC_DEFINE(M_UDFDS, "udf_ds", "UDF Dirstream structure"); 11194663Sscottl 112101895Sscottl#define UDF_INVALID_BMAP -1 113101202Sscottl 11494663Sscottlint 11594663Sscottludf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td) 11694663Sscottl{ 11794663Sscottl int error; 11894663Sscottl struct vnode *vp; 11994663Sscottl 120138290Sphk error = getnewvnode("udf", mp, &udf_vnodeops, &vp); 12194663Sscottl if (error) { 12294663Sscottl printf("udf_allocv: failed to allocate new vnode\n"); 12394663Sscottl return (error); 12494663Sscottl } 12594663Sscottl 12694663Sscottl *vpp = vp; 12794663Sscottl return (0); 12894663Sscottl} 12994663Sscottl 13094663Sscottl/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */ 13194663Sscottlstatic mode_t 13294663Sscottludf_permtomode(struct udf_node *node) 13394663Sscottl{ 13494795Sasmodai uint32_t perm; 135130994Sscottl uint16_t flags; 13694663Sscottl mode_t mode; 13794663Sscottl 138130994Sscottl perm = le32toh(node->fentry->perm); 139130994Sscottl flags = le16toh(node->fentry->icbtag.flags); 14094663Sscottl 14194663Sscottl mode = perm & UDF_FENTRY_PERM_USER_MASK; 14294663Sscottl mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2); 14394663Sscottl mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4); 14494663Sscottl mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4); 14594663Sscottl mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6); 14694663Sscottl mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8); 14794663Sscottl 14894663Sscottl return (mode); 14994663Sscottl} 150111742Sdes 15194663Sscottlstatic int 15294663Sscottludf_access(struct vop_access_args *a) 15394663Sscottl{ 15494663Sscottl struct vnode *vp; 15594663Sscottl struct udf_node *node; 156184413Strasz accmode_t accmode; 157184413Strasz mode_t mode; 15894663Sscottl 15994663Sscottl vp = a->a_vp; 16094663Sscottl node = VTON(vp); 161184413Strasz accmode = a->a_accmode; 16294663Sscottl 163184413Strasz if (accmode & VWRITE) { 16494663Sscottl switch (vp->v_type) { 16594663Sscottl case VDIR: 16694663Sscottl case VLNK: 16794663Sscottl case VREG: 16894663Sscottl return (EROFS); 16994663Sscottl /* NOT REACHED */ 17094663Sscottl default: 17194663Sscottl break; 17294663Sscottl } 17394663Sscottl } 17494663Sscottl 17594663Sscottl mode = udf_permtomode(node); 17694663Sscottl 17794663Sscottl return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid, 178184413Strasz accmode, a->a_cred, NULL)); 17994663Sscottl} 18094663Sscottl 181165500Spavstatic int 182165500Spavudf_open(struct vop_open_args *ap) { 183165500Spav struct udf_node *np = VTON(ap->a_vp); 184165500Spav off_t fsize; 185165500Spav 186165500Spav fsize = le64toh(np->fentry->inf_len); 187165500Spav vnode_create_vobject(ap->a_vp, fsize, ap->a_td); 188165500Spav return 0; 189165500Spav} 190165500Spav 191179060Smarkusstatic const int mon_lens[2][12] = { 192179060Smarkus {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, 193179060Smarkus {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} 19494663Sscottl}; 19594663Sscottl 19694663Sscottlstatic int 19794663Sscottludf_isaleapyear(int year) 19894663Sscottl{ 19994663Sscottl int i; 20094663Sscottl 20194663Sscottl i = (year % 4) ? 0 : 1; 20294663Sscottl i &= (year % 100) ? 1 : 0; 20394663Sscottl i |= (year % 400) ? 0 : 1; 20494663Sscottl 20594663Sscottl return i; 20694663Sscottl} 20794663Sscottl 20894663Sscottl/* 20994663Sscottl * Timezone calculation compliments of Julian Elischer <julian@elischer.org>. 21094663Sscottl */ 21194663Sscottlstatic void 21294663Sscottludf_timetotimespec(struct timestamp *time, struct timespec *t) 21394663Sscottl{ 214179060Smarkus int i, lpyear, daysinyear, year, startyear; 21594663Sscottl union { 21694795Sasmodai uint16_t u_tz_offset; 21794663Sscottl int16_t s_tz_offset; 21894663Sscottl } tz; 21994663Sscottl 220179060Smarkus /* 221179060Smarkus * DirectCD seems to like using bogus year values. 222179060Smarkus * Don't trust time->month as it will be used for an array index. 223179060Smarkus */ 224130994Sscottl year = le16toh(time->year); 225179060Smarkus if (year < 1970 || time->month < 1 || time->month > 12) { 22694663Sscottl t->tv_sec = 0; 227179060Smarkus t->tv_nsec = 0; 22894663Sscottl return; 22994663Sscottl } 23094663Sscottl 23194663Sscottl /* Calculate the time and day */ 23294663Sscottl t->tv_sec = time->second; 23394663Sscottl t->tv_sec += time->minute * 60; 23494663Sscottl t->tv_sec += time->hour * 3600; 235179060Smarkus t->tv_sec += (time->day - 1) * 3600 * 24; 23694663Sscottl 237146121Sbrueffer /* Calculate the month */ 238130994Sscottl lpyear = udf_isaleapyear(year); 239179060Smarkus t->tv_sec += mon_lens[lpyear][time->month - 1] * 3600 * 24; 24094663Sscottl 24194663Sscottl /* Speed up the calculation */ 242179060Smarkus startyear = 1970; 243179060Smarkus if (year > 2009) { 244179060Smarkus t->tv_sec += 1262304000; 245179060Smarkus startyear += 40; 246179060Smarkus } else if (year > 1999) { 247179060Smarkus t->tv_sec += 946684800; 248179060Smarkus startyear += 30; 249179060Smarkus } else if (year > 1989) { 250179060Smarkus t->tv_sec += 631152000; 251179060Smarkus startyear += 20; 252179060Smarkus } else if (year > 1979) { 25394663Sscottl t->tv_sec += 315532800; 254179060Smarkus startyear += 10; 25594663Sscottl } 25694663Sscottl 257179060Smarkus daysinyear = (year - startyear) * 365; 258179060Smarkus for (i = startyear; i < year; i++) 259179060Smarkus daysinyear += udf_isaleapyear(i); 260179060Smarkus t->tv_sec += daysinyear * 3600 * 24; 261179060Smarkus 262179060Smarkus /* Calculate microseconds */ 263179060Smarkus t->tv_nsec = time->centisec * 10000 + time->hund_usec * 100 + 264179060Smarkus time->usec; 265179060Smarkus 26694663Sscottl /* 26794663Sscottl * Calculate the time zone. The timezone is 12 bit signed 2's 268146121Sbrueffer * complement, so we gotta do some extra magic to handle it right. 26994663Sscottl */ 270130994Sscottl tz.u_tz_offset = le16toh(time->type_tz); 27194663Sscottl tz.u_tz_offset &= 0x0fff; 27294663Sscottl if (tz.u_tz_offset & 0x0800) 27394663Sscottl tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */ 274179060Smarkus if ((le16toh(time->type_tz) & 0x1000) && (tz.s_tz_offset != -2047)) 27594663Sscottl t->tv_sec -= tz.s_tz_offset * 60; 27694663Sscottl 27794663Sscottl return; 27894663Sscottl} 27994663Sscottl 28094663Sscottlstatic int 28194663Sscottludf_getattr(struct vop_getattr_args *a) 28294663Sscottl{ 28394663Sscottl struct vnode *vp; 28494663Sscottl struct udf_node *node; 28594663Sscottl struct vattr *vap; 28694663Sscottl struct file_entry *fentry; 28794663Sscottl struct timespec ts; 28894663Sscottl 28994663Sscottl ts.tv_sec = 0; 29094663Sscottl 29194663Sscottl vp = a->a_vp; 29294663Sscottl vap = a->a_vap; 29394663Sscottl node = VTON(vp); 29494663Sscottl fentry = node->fentry; 29594663Sscottl 296143756Sphk vap->va_fsid = dev2udev(node->udfmp->im_dev); 29794663Sscottl vap->va_fileid = node->hash_id; 29894663Sscottl vap->va_mode = udf_permtomode(node); 299130994Sscottl vap->va_nlink = le16toh(fentry->link_cnt); 30094663Sscottl /* 30194663Sscottl * XXX The spec says that -1 is valid for uid/gid and indicates an 30294663Sscottl * invalid uid/gid. How should this be represented? 30394663Sscottl */ 304130994Sscottl vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid); 305130994Sscottl vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid); 30694663Sscottl udf_timetotimespec(&fentry->atime, &vap->va_atime); 30794663Sscottl udf_timetotimespec(&fentry->mtime, &vap->va_mtime); 30894663Sscottl vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */ 309183214Skib vap->va_rdev = NODEV; 31094663Sscottl if (vp->v_type & VDIR) { 31194663Sscottl /* 31294663Sscottl * Directories that are recorded within their ICB will show 31394663Sscottl * as having 0 blocks recorded. Since tradition dictates 31494663Sscottl * that directories consume at least one logical block, 31594663Sscottl * make it appear so. 31694663Sscottl */ 31794663Sscottl if (fentry->logblks_rec != 0) { 318130994Sscottl vap->va_size = 319130994Sscottl le64toh(fentry->logblks_rec) * node->udfmp->bsize; 32094663Sscottl } else { 32194663Sscottl vap->va_size = node->udfmp->bsize; 32294663Sscottl } 32394663Sscottl } else { 324130994Sscottl vap->va_size = le64toh(fentry->inf_len); 32594663Sscottl } 32694663Sscottl vap->va_flags = 0; 32794663Sscottl vap->va_gen = 1; 32894663Sscottl vap->va_blocksize = node->udfmp->bsize; 329130994Sscottl vap->va_bytes = le64toh(fentry->inf_len); 33094663Sscottl vap->va_type = vp->v_type; 33194663Sscottl vap->va_filerev = 0; /* XXX */ 33294663Sscottl return (0); 33394663Sscottl} 33494663Sscottl 335188245Sjhbstatic int 336188245Sjhbudf_setattr(struct vop_setattr_args *a) 337188245Sjhb{ 338188245Sjhb struct vnode *vp; 339188245Sjhb struct vattr *vap; 340188245Sjhb 341188245Sjhb vp = a->a_vp; 342188245Sjhb vap = a->a_vap; 343188245Sjhb if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || 344188245Sjhb vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 345188245Sjhb vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) 346188245Sjhb return (EROFS); 347188245Sjhb if (vap->va_size != (u_quad_t)VNOVAL) { 348188245Sjhb switch (vp->v_type) { 349188245Sjhb case VDIR: 350188245Sjhb return (EISDIR); 351188245Sjhb case VLNK: 352188245Sjhb case VREG: 353188245Sjhb return (EROFS); 354188245Sjhb case VCHR: 355188245Sjhb case VBLK: 356188245Sjhb case VSOCK: 357188245Sjhb case VFIFO: 358188245Sjhb case VNON: 359188245Sjhb case VBAD: 360188245Sjhb case VMARKER: 361188245Sjhb return (0); 362188245Sjhb } 363188245Sjhb } 364188245Sjhb return (0); 365188245Sjhb} 366188245Sjhb 36794663Sscottl/* 368130994Sscottl * File specific ioctls. 36994663Sscottl */ 37094663Sscottlstatic int 37194663Sscottludf_ioctl(struct vop_ioctl_args *a) 37294663Sscottl{ 373126532Sscottl printf("%s called\n", __func__); 374104005Sphk return (ENOTTY); 37594663Sscottl} 37694663Sscottl 37794663Sscottl/* 37894663Sscottl * I'm not sure that this has much value in a read-only filesystem, but 37994663Sscottl * cd9660 has it too. 38094663Sscottl */ 38194663Sscottlstatic int 38294663Sscottludf_pathconf(struct vop_pathconf_args *a) 38394663Sscottl{ 38494663Sscottl 38594663Sscottl switch (a->a_name) { 38694663Sscottl case _PC_LINK_MAX: 38794663Sscottl *a->a_retval = 65535; 38894663Sscottl return (0); 38994663Sscottl case _PC_NAME_MAX: 39094663Sscottl *a->a_retval = NAME_MAX; 39194663Sscottl return (0); 39294663Sscottl case _PC_PATH_MAX: 39394663Sscottl *a->a_retval = PATH_MAX; 39494663Sscottl return (0); 39594663Sscottl case _PC_NO_TRUNC: 39694663Sscottl *a->a_retval = 1; 39794663Sscottl return (0); 39894663Sscottl default: 39994663Sscottl return (EINVAL); 40094663Sscottl } 40194663Sscottl} 40294663Sscottl 403188245Sjhbstatic int 404188245Sjhbudf_print(struct vop_print_args *ap) 405188245Sjhb{ 406188245Sjhb struct vnode *vp = ap->a_vp; 407188245Sjhb struct udf_node *node = VTON(vp); 408188245Sjhb 409188245Sjhb printf(" ino %lu, on dev %s", (u_long)node->hash_id, 410188245Sjhb devtoname(node->udfmp->im_dev)); 411188245Sjhb if (vp->v_type == VFIFO) 412188245Sjhb fifo_printinfo(vp); 413188245Sjhb printf("\n"); 414188245Sjhb return (0); 415188245Sjhb} 416188245Sjhb 417166030Spav#define lblkno(udfmp, loc) ((loc) >> (udfmp)->bshift) 418166030Spav#define blkoff(udfmp, loc) ((loc) & (udfmp)->bmask) 419189067Savg#define lblktosize(udfmp, blk) ((blk) << (udfmp)->bshift) 420166030Spav 421189068Savgstatic inline int 422189068Savgis_data_in_fentry(const struct udf_node *node) 423189068Savg{ 424189068Savg const struct file_entry *fentry = node->fentry; 425189068Savg 426189068Savg return ((le16toh(fentry->icbtag.flags) & 0x7) == 3); 427189068Savg} 428189068Savg 42994663Sscottlstatic int 430166030Spavudf_read(struct vop_read_args *ap) 43194663Sscottl{ 432166030Spav struct vnode *vp = ap->a_vp; 433166030Spav struct uio *uio = ap->a_uio; 43494663Sscottl struct udf_node *node = VTON(vp); 435166030Spav struct udf_mnt *udfmp; 436189068Savg struct file_entry *fentry; 43794663Sscottl struct buf *bp; 438189068Savg uint8_t *data; 439166030Spav daddr_t lbn, rablock; 440166030Spav off_t diff, fsize; 441231949Skib ssize_t n; 44294663Sscottl int error = 0; 443231949Skib long size, on; 44494663Sscottl 445166030Spav if (uio->uio_resid == 0) 446166030Spav return (0); 44794663Sscottl if (uio->uio_offset < 0) 44894663Sscottl return (EINVAL); 449189068Savg 450189068Savg if (is_data_in_fentry(node)) { 451189068Savg fentry = node->fentry; 452189068Savg data = &fentry->data[le32toh(fentry->l_ea)]; 453189068Savg fsize = le32toh(fentry->l_ad); 454189068Savg 455189068Savg n = uio->uio_resid; 456189068Savg diff = fsize - uio->uio_offset; 457189068Savg if (diff <= 0) 458189068Savg return (0); 459189068Savg if (diff < n) 460189068Savg n = diff; 461189068Savg error = uiomove(data + uio->uio_offset, (int)n, uio); 462189068Savg return (error); 463189068Savg } 464189068Savg 465130994Sscottl fsize = le64toh(node->fentry->inf_len); 466166030Spav udfmp = node->udfmp; 467166030Spav do { 468166030Spav lbn = lblkno(udfmp, uio->uio_offset); 469166030Spav on = blkoff(udfmp, uio->uio_offset); 470166030Spav n = min((u_int)(udfmp->bsize - on), 471166030Spav uio->uio_resid); 472166030Spav diff = fsize - uio->uio_offset; 473166030Spav if (diff <= 0) 474166030Spav return (0); 475166030Spav if (diff < n) 476166030Spav n = diff; 477166030Spav size = udfmp->bsize; 478166030Spav rablock = lbn + 1; 479166030Spav if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 480166030Spav if (lblktosize(udfmp, rablock) < fsize) { 481248282Skib error = cluster_read(vp, fsize, lbn, size, 482248282Skib NOCRED, uio->uio_resid, 483248282Skib (ap->a_ioflag >> 16), 0, &bp); 484166030Spav } else { 485166030Spav error = bread(vp, lbn, size, NOCRED, &bp); 486166030Spav } 487166030Spav } else { 488166030Spav error = bread(vp, lbn, size, NOCRED, &bp); 489166030Spav } 490166030Spav n = min(n, size - bp->b_resid); 491166030Spav if (error) { 49294663Sscottl brelse(bp); 493166030Spav return (error); 494166030Spav } 49594663Sscottl 496166030Spav error = uiomove(bp->b_data + on, (int)n, uio); 497166030Spav brelse(bp); 498166030Spav } while (error == 0 && uio->uio_resid > 0 && n != 0); 49994663Sscottl return (error); 50094663Sscottl} 50194663Sscottl 50294663Sscottl/* 50394663Sscottl * Call the OSTA routines to translate the name from a CS0 dstring to a 50494663Sscottl * 16-bit Unicode String. Hooks need to be placed in here to translate from 505122102Sscottl * Unicode to the encoding that the kernel/user expects. Return the length 506122102Sscottl * of the translated string. 50794663Sscottl */ 50894663Sscottlstatic int 509122102Sscottludf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp) 51094663Sscottl{ 51194663Sscottl unicode_t *transname; 512122102Sscottl char *unibuf, *unip; 513146984Simura int i, destlen; 514146984Simura ssize_t unilen = 0; 515122102Sscottl size_t destleft = MAXNAMLEN; 51694663Sscottl 517122102Sscottl /* Convert 16-bit Unicode to destname */ 518122102Sscottl if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) { 519122102Sscottl /* allocate a buffer big enough to hold an 8->16 bit expansion */ 520122102Sscottl unibuf = uma_zalloc(udf_zone_trans, M_WAITOK); 521122102Sscottl unip = unibuf; 522146984Simura if ((unilen = (ssize_t)udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) { 523122102Sscottl printf("udf: Unicode translation failed\n"); 524122102Sscottl uma_zfree(udf_zone_trans, unibuf); 525122102Sscottl return 0; 526122102Sscottl } 52794663Sscottl 528122102Sscottl while (unilen > 0 && destleft > 0) { 529278141Sdim udf_iconv->conv(udfmp->im_d2l, __DECONST(const char **, 530278141Sdim &unibuf), (size_t *)&unilen, (char **)&destname, 531278141Sdim &destleft); 532122102Sscottl /* Unconverted character found */ 533122102Sscottl if (unilen > 0 && destleft > 0) { 534122102Sscottl *destname++ = '?'; 535122102Sscottl destleft--; 536122102Sscottl unibuf += 2; 537122102Sscottl unilen -= 2; 538122102Sscottl } 539122102Sscottl } 540122102Sscottl uma_zfree(udf_zone_trans, unip); 541122102Sscottl *destname = '\0'; 542122102Sscottl destlen = MAXNAMLEN - (int)destleft; 543122102Sscottl } else { 544122102Sscottl /* allocate a buffer big enough to hold an 8->16 bit expansion */ 545122102Sscottl transname = uma_zalloc(udf_zone_trans, M_WAITOK); 54694663Sscottl 547146984Simura if ((unilen = (ssize_t)udf_UncompressUnicode(len, cs0string, transname)) == -1) { 548122102Sscottl printf("udf: Unicode translation failed\n"); 549122102Sscottl uma_zfree(udf_zone_trans, transname); 550122102Sscottl return 0; 55194663Sscottl } 552122102Sscottl 553122102Sscottl for (i = 0; i < unilen ; i++) { 554122102Sscottl if (transname[i] & 0xff00) { 555122102Sscottl destname[i] = '.'; /* Fudge the 16bit chars */ 556122102Sscottl } else { 557122102Sscottl destname[i] = transname[i] & 0xff; 558122102Sscottl } 559122102Sscottl } 560122102Sscottl uma_zfree(udf_zone_trans, transname); 561122102Sscottl destname[unilen] = 0; 562146984Simura destlen = (int)unilen; 56394663Sscottl } 56494663Sscottl 565122102Sscottl return (destlen); 56694663Sscottl} 56794663Sscottl 56894663Sscottl/* 56994663Sscottl * Compare a CS0 dstring with a name passed in from the VFS layer. Return 570146121Sbrueffer * 0 on a successful match, nonzero otherwise. Unicode work may need to be done 57194663Sscottl * here also. 57294663Sscottl */ 57394663Sscottlstatic int 574122102Sscottludf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp) 57594663Sscottl{ 576102169Sscottl char *transname; 577102169Sscottl int error = 0; 57894663Sscottl 579102169Sscottl /* This is overkill, but not worth creating a new zone */ 580111119Simp transname = uma_zalloc(udf_zone_trans, M_WAITOK); 58194663Sscottl 582122102Sscottl cs0len = udf_transname(cs0string, transname, cs0len, udfmp); 583102169Sscottl 58494663Sscottl /* Easy check. If they aren't the same length, they aren't equal */ 585102169Sscottl if ((cs0len == 0) || (cs0len != cmplen)) 586102169Sscottl error = -1; 587102169Sscottl else 588102169Sscottl error = bcmp(transname, cmpname, cmplen); 58994663Sscottl 590102169Sscottl uma_zfree(udf_zone_trans, transname); 591102169Sscottl return (error); 59294663Sscottl} 59394663Sscottl 59494663Sscottlstruct udf_uiodir { 59594663Sscottl struct dirent *dirent; 59694663Sscottl u_long *cookies; 59794663Sscottl int ncookies; 59894663Sscottl int acookies; 59994663Sscottl int eofflag; 60094663Sscottl}; 60194663Sscottl 60294663Sscottlstatic int 60394663Sscottludf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie) 60494663Sscottl{ 60594663Sscottl if (uiodir->cookies != NULL) { 60694663Sscottl if (++uiodir->acookies > uiodir->ncookies) { 60794663Sscottl uiodir->eofflag = 0; 60894663Sscottl return (-1); 60994663Sscottl } 61094663Sscottl *uiodir->cookies++ = cookie; 61194663Sscottl } 61294663Sscottl 61394663Sscottl if (uio->uio_resid < de_size) { 61494663Sscottl uiodir->eofflag = 0; 61594663Sscottl return (-1); 61694663Sscottl } 61794663Sscottl 618111741Sdes return (uiomove(uiodir->dirent, de_size, uio)); 61994663Sscottl} 62094663Sscottl 621101890Sscottlstatic struct udf_dirstream * 622101890Sscottludf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp) 623101890Sscottl{ 624101890Sscottl struct udf_dirstream *ds; 625101890Sscottl 626111119Simp ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO); 627101890Sscottl 628101890Sscottl ds->node = node; 629101890Sscottl ds->offset = offset; 630101890Sscottl ds->udfmp = udfmp; 631101890Sscottl ds->fsize = fsize; 632101890Sscottl 633101890Sscottl return (ds); 634101890Sscottl} 635101890Sscottl 636101890Sscottlstatic struct fileid_desc * 637101890Sscottludf_getfid(struct udf_dirstream *ds) 638101890Sscottl{ 639101890Sscottl struct fileid_desc *fid; 640101890Sscottl int error, frag_size = 0, total_fid_size; 641101890Sscottl 642101890Sscottl /* End of directory? */ 643101890Sscottl if (ds->offset + ds->off >= ds->fsize) { 644101890Sscottl ds->error = 0; 645101890Sscottl return (NULL); 646101890Sscottl } 647101890Sscottl 648101890Sscottl /* Grab the first extent of the directory */ 649101890Sscottl if (ds->off == 0) { 650101890Sscottl ds->size = 0; 651101890Sscottl error = udf_readatoffset(ds->node, &ds->size, ds->offset, 652101890Sscottl &ds->bp, &ds->data); 653101890Sscottl if (error) { 654101890Sscottl ds->error = error; 655127603Sscottl if (ds->bp != NULL) 656127603Sscottl brelse(ds->bp); 657101890Sscottl return (NULL); 658101890Sscottl } 659101890Sscottl } 660101890Sscottl 661101895Sscottl /* 662101895Sscottl * Clean up from a previous fragmented FID. 663101895Sscottl * XXX Is this the right place for this? 664101895Sscottl */ 665101890Sscottl if (ds->fid_fragment && ds->buf != NULL) { 666101890Sscottl ds->fid_fragment = 0; 667184205Sdes free(ds->buf, M_UDFFID); 668101890Sscottl } 669101890Sscottl 670101890Sscottl fid = (struct fileid_desc*)&ds->data[ds->off]; 671101890Sscottl 672101890Sscottl /* 673101890Sscottl * Check to see if the fid is fragmented. The first test 674101890Sscottl * ensures that we don't wander off the end of the buffer 675101890Sscottl * looking for the l_iu and l_fi fields. 676101890Sscottl */ 677101890Sscottl if (ds->off + UDF_FID_SIZE > ds->size || 678130994Sscottl ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){ 679101890Sscottl 680101890Sscottl /* Copy what we have of the fid into a buffer */ 681101890Sscottl frag_size = ds->size - ds->off; 682101890Sscottl if (frag_size >= ds->udfmp->bsize) { 683101890Sscottl printf("udf: invalid FID fragment\n"); 684101890Sscottl ds->error = EINVAL; 685101890Sscottl return (NULL); 686101890Sscottl } 687101890Sscottl 688101890Sscottl /* 689101890Sscottl * File ID descriptors can only be at most one 690101890Sscottl * logical sector in size. 691101890Sscottl */ 692184205Sdes ds->buf = malloc(ds->udfmp->bsize, M_UDFFID, 693111119Simp M_WAITOK | M_ZERO); 694101890Sscottl bcopy(fid, ds->buf, frag_size); 695101890Sscottl 696101890Sscottl /* Reduce all of the casting magic */ 697101890Sscottl fid = (struct fileid_desc*)ds->buf; 698101890Sscottl 699101890Sscottl if (ds->bp != NULL) 700101890Sscottl brelse(ds->bp); 701101890Sscottl 702101890Sscottl /* Fetch the next allocation */ 703101890Sscottl ds->offset += ds->size; 704101890Sscottl ds->size = 0; 705101890Sscottl error = udf_readatoffset(ds->node, &ds->size, ds->offset, 706101890Sscottl &ds->bp, &ds->data); 707101890Sscottl if (error) { 708101890Sscottl ds->error = error; 709101890Sscottl return (NULL); 710101890Sscottl } 711101890Sscottl 712101890Sscottl /* 713101890Sscottl * If the fragment was so small that we didn't get 714101890Sscottl * the l_iu and l_fi fields, copy those in. 715101890Sscottl */ 716101890Sscottl if (frag_size < UDF_FID_SIZE) 717101890Sscottl bcopy(ds->data, &ds->buf[frag_size], 718101890Sscottl UDF_FID_SIZE - frag_size); 719101890Sscottl 720101890Sscottl /* 721101890Sscottl * Now that we have enough of the fid to work with, 722101890Sscottl * copy in the rest of the fid from the new 723101890Sscottl * allocation. 724101890Sscottl */ 725130994Sscottl total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi; 726101890Sscottl if (total_fid_size > ds->udfmp->bsize) { 727101890Sscottl printf("udf: invalid FID\n"); 728101890Sscottl ds->error = EIO; 729101890Sscottl return (NULL); 730101890Sscottl } 731101890Sscottl bcopy(ds->data, &ds->buf[frag_size], 732101890Sscottl total_fid_size - frag_size); 733101890Sscottl 734101890Sscottl ds->fid_fragment = 1; 735101890Sscottl } else { 736130994Sscottl total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE; 737101890Sscottl } 738101890Sscottl 739101890Sscottl /* 740101890Sscottl * Update the offset. Align on a 4 byte boundary because the 741101895Sscottl * UDF spec says so. 742101890Sscottl */ 743189364Savg ds->this_off = ds->offset + ds->off; 744101890Sscottl if (!ds->fid_fragment) { 745101890Sscottl ds->off += (total_fid_size + 3) & ~0x03; 746101890Sscottl } else { 747101890Sscottl ds->off = (total_fid_size - frag_size + 3) & ~0x03; 748101890Sscottl } 749101890Sscottl 750101890Sscottl return (fid); 751101890Sscottl} 752101890Sscottl 753101890Sscottlstatic void 754101890Sscottludf_closedir(struct udf_dirstream *ds) 755101890Sscottl{ 756101890Sscottl 757101890Sscottl if (ds->bp != NULL) 758101890Sscottl brelse(ds->bp); 759101890Sscottl 760101890Sscottl if (ds->fid_fragment && ds->buf != NULL) 761184205Sdes free(ds->buf, M_UDFFID); 762101890Sscottl 763101890Sscottl uma_zfree(udf_zone_ds, ds); 764101890Sscottl} 765101890Sscottl 76694663Sscottlstatic int 76794663Sscottludf_readdir(struct vop_readdir_args *a) 76894663Sscottl{ 76994663Sscottl struct vnode *vp; 77094663Sscottl struct uio *uio; 77194663Sscottl struct dirent dir; 77294663Sscottl struct udf_node *node; 773122102Sscottl struct udf_mnt *udfmp; 77494663Sscottl struct fileid_desc *fid; 77594663Sscottl struct udf_uiodir uiodir; 776101890Sscottl struct udf_dirstream *ds; 77794663Sscottl u_long *cookies = NULL; 77894663Sscottl int ncookies; 779102170Sscottl int error = 0; 78094663Sscottl 78194663Sscottl vp = a->a_vp; 78294663Sscottl uio = a->a_uio; 78394663Sscottl node = VTON(vp); 784122102Sscottl udfmp = node->udfmp; 78594663Sscottl uiodir.eofflag = 1; 78694663Sscottl 78794663Sscottl if (a->a_ncookies != NULL) { 78894663Sscottl /* 78994663Sscottl * Guess how many entries are needed. If we run out, this 79094663Sscottl * function will be called again and thing will pick up were 79194663Sscottl * it left off. 79294663Sscottl */ 79394663Sscottl ncookies = uio->uio_resid / 8; 794184205Sdes cookies = malloc(sizeof(u_long) * ncookies, 795111119Simp M_TEMP, M_WAITOK); 79694663Sscottl if (cookies == NULL) 79794663Sscottl return (ENOMEM); 79894663Sscottl uiodir.ncookies = ncookies; 79994663Sscottl uiodir.cookies = cookies; 80094663Sscottl uiodir.acookies = 0; 80194663Sscottl } else { 80294663Sscottl uiodir.cookies = NULL; 80394663Sscottl } 80494663Sscottl 80594663Sscottl /* 80694663Sscottl * Iterate through the file id descriptors. Give the parent dir 807101895Sscottl * entry special attention. 80894663Sscottl */ 809130994Sscottl ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len), 810101890Sscottl node->udfmp); 81194663Sscottl 812101890Sscottl while ((fid = udf_getfid(ds)) != NULL) { 81394663Sscottl 81494663Sscottl /* XXX Should we return an error on a bad fid? */ 81594663Sscottl if (udf_checktag(&fid->tag, TAGID_FID)) { 81694663Sscottl printf("Invalid FID tag\n"); 817123215Sscottl hexdump(fid, UDF_FID_SIZE, NULL, 0); 818101890Sscottl error = EIO; 81994663Sscottl break; 82094663Sscottl } 82194663Sscottl 82294663Sscottl /* Is this a deleted file? */ 823101317Sscottl if (fid->file_char & UDF_FILE_CHAR_DEL) 824101890Sscottl continue; 82594663Sscottl 826101317Sscottl if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 82794663Sscottl /* Do up the '.' and '..' entries. Dummy values are 82894663Sscottl * used for the cookies since the offset here is 82994663Sscottl * usually zero, and NFS doesn't like that value 83094663Sscottl */ 831102170Sscottl dir.d_fileno = node->hash_id; 832102170Sscottl dir.d_type = DT_DIR; 833102170Sscottl dir.d_name[0] = '.'; 834140250Sscottl dir.d_name[1] = '\0'; 835102170Sscottl dir.d_namlen = 1; 836102170Sscottl dir.d_reclen = GENERIC_DIRSIZ(&dir); 837102170Sscottl uiodir.dirent = &dir; 838111742Sdes error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1); 83994663Sscottl if (error) 84094663Sscottl break; 84194663Sscottl 842102170Sscottl dir.d_fileno = udf_getid(&fid->icb); 843102170Sscottl dir.d_type = DT_DIR; 844102170Sscottl dir.d_name[0] = '.'; 845102170Sscottl dir.d_name[1] = '.'; 846140250Sscottl dir.d_name[2] = '\0'; 847102170Sscottl dir.d_namlen = 2; 848102170Sscottl dir.d_reclen = GENERIC_DIRSIZ(&dir); 849102170Sscottl uiodir.dirent = &dir; 850102170Sscottl error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2); 85194663Sscottl } else { 85294663Sscottl dir.d_namlen = udf_transname(&fid->data[fid->l_iu], 853122102Sscottl &dir.d_name[0], fid->l_fi, udfmp); 85494663Sscottl dir.d_fileno = udf_getid(&fid->icb); 855101317Sscottl dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ? 856101317Sscottl DT_DIR : DT_UNKNOWN; 85794663Sscottl dir.d_reclen = GENERIC_DIRSIZ(&dir); 85894663Sscottl uiodir.dirent = &dir; 859101890Sscottl error = udf_uiodir(&uiodir, dir.d_reclen, uio, 860101890Sscottl ds->this_off); 86194663Sscottl } 862188815Savg if (error) 86394663Sscottl break; 864189302Savg uio->uio_offset = ds->offset + ds->off; 86594663Sscottl } 86694663Sscottl 86794663Sscottl /* tell the calling layer whether we need to be called again */ 86894663Sscottl *a->a_eofflag = uiodir.eofflag; 86994663Sscottl 870188816Savg if (error < 0) 871188815Savg error = 0; 872101890Sscottl if (!error) 873101890Sscottl error = ds->error; 87494663Sscottl 875101890Sscottl udf_closedir(ds); 876101890Sscottl 87794663Sscottl if (a->a_ncookies != NULL) { 87894663Sscottl if (error) 879184205Sdes free(cookies, M_TEMP); 88094663Sscottl else { 88194663Sscottl *a->a_ncookies = uiodir.acookies; 88294663Sscottl *a->a_cookies = cookies; 88394663Sscottl } 88494663Sscottl } 88594663Sscottl 88694663Sscottl return (error); 88794663Sscottl} 88894663Sscottl 88994663Sscottlstatic int 89094663Sscottludf_readlink(struct vop_readlink_args *ap) 89194663Sscottl{ 892188251Sjhb struct path_component *pc, *end; 893188251Sjhb struct vnode *vp; 894188251Sjhb struct uio uio; 895188251Sjhb struct iovec iov[1]; 896188251Sjhb struct udf_node *node; 897188251Sjhb void *buf; 898188251Sjhb char *cp; 899188251Sjhb int error, len, root; 900188251Sjhb 901188251Sjhb /* 902188251Sjhb * A symbolic link in UDF is a list of variable-length path 903188251Sjhb * component structures. We build a pathname in the caller's 904188251Sjhb * uio by traversing this list. 905188251Sjhb */ 906188251Sjhb vp = ap->a_vp; 907188251Sjhb node = VTON(vp); 908188251Sjhb len = le64toh(node->fentry->inf_len); 909209425Savg buf = malloc(len, M_DEVBUF, M_WAITOK); 910208671Savg iov[0].iov_len = len; 911188251Sjhb iov[0].iov_base = buf; 912188251Sjhb uio.uio_iov = iov; 913188251Sjhb uio.uio_iovcnt = 1; 914188251Sjhb uio.uio_offset = 0; 915188251Sjhb uio.uio_resid = iov[0].iov_len; 916188251Sjhb uio.uio_segflg = UIO_SYSSPACE; 917188251Sjhb uio.uio_rw = UIO_READ; 918188251Sjhb uio.uio_td = curthread; 919188251Sjhb error = VOP_READ(vp, &uio, 0, ap->a_cred); 920188251Sjhb if (error) 921188251Sjhb goto error; 922188251Sjhb 923188251Sjhb pc = buf; 924188251Sjhb end = (void *)((char *)buf + len); 925188251Sjhb root = 0; 926188251Sjhb while (pc < end) { 927188251Sjhb switch (pc->type) { 928188251Sjhb case UDF_PATH_ROOT: 929188251Sjhb /* Only allow this at the beginning of a path. */ 930188251Sjhb if ((void *)pc != buf) { 931188251Sjhb error = EINVAL; 932188251Sjhb goto error; 933188251Sjhb } 934188251Sjhb cp = "/"; 935188251Sjhb len = 1; 936188251Sjhb root = 1; 937188251Sjhb break; 938188251Sjhb case UDF_PATH_DOT: 939188251Sjhb cp = "."; 940188251Sjhb len = 1; 941188251Sjhb break; 942188251Sjhb case UDF_PATH_DOTDOT: 943188251Sjhb cp = ".."; 944188251Sjhb len = 2; 945188251Sjhb break; 946188251Sjhb case UDF_PATH_PATH: 947188251Sjhb if (pc->length == 0) { 948188251Sjhb error = EINVAL; 949188251Sjhb goto error; 950188251Sjhb } 951188251Sjhb /* 952188251Sjhb * XXX: We only support CS8 which appears to map 953188251Sjhb * to ASCII directly. 954188251Sjhb */ 955188251Sjhb switch (pc->identifier[0]) { 956188251Sjhb case 8: 957188251Sjhb cp = pc->identifier + 1; 958188251Sjhb len = pc->length - 1; 959188251Sjhb break; 960188251Sjhb default: 961188251Sjhb error = EOPNOTSUPP; 962188251Sjhb goto error; 963188251Sjhb } 964188251Sjhb break; 965188251Sjhb default: 966188251Sjhb error = EINVAL; 967188251Sjhb goto error; 968188251Sjhb } 969188251Sjhb 970188251Sjhb /* 971188251Sjhb * If this is not the first component, insert a path 972188251Sjhb * separator. 973188251Sjhb */ 974188251Sjhb if (pc != buf) { 975188251Sjhb /* If we started with root we already have a "/". */ 976188251Sjhb if (root) 977188251Sjhb goto skipslash; 978188251Sjhb root = 0; 979188251Sjhb if (ap->a_uio->uio_resid < 1) { 980188251Sjhb error = ENAMETOOLONG; 981188251Sjhb goto error; 982188251Sjhb } 983188251Sjhb error = uiomove("/", 1, ap->a_uio); 984188251Sjhb if (error) 985188251Sjhb break; 986188251Sjhb } 987188251Sjhb skipslash: 988188251Sjhb 989188251Sjhb /* Append string at 'cp' of length 'len' to our path. */ 990188251Sjhb if (len > ap->a_uio->uio_resid) { 991188251Sjhb error = ENAMETOOLONG; 992188251Sjhb goto error; 993188251Sjhb } 994188251Sjhb error = uiomove(cp, len, ap->a_uio); 995188251Sjhb if (error) 996188251Sjhb break; 997188251Sjhb 998188251Sjhb /* Advance to next component. */ 999188251Sjhb pc = (void *)((char *)pc + 4 + pc->length); 1000188251Sjhb } 1001188251Sjhberror: 1002188251Sjhb free(buf, M_DEVBUF); 1003188251Sjhb return (error); 100494663Sscottl} 100594663Sscottl 100694663Sscottlstatic int 100794663Sscottludf_strategy(struct vop_strategy_args *a) 100894663Sscottl{ 100994663Sscottl struct buf *bp; 101094663Sscottl struct vnode *vp; 101194663Sscottl struct udf_node *node; 1012189067Savg struct bufobj *bo; 1013189067Savg off_t offset; 1014189067Savg uint32_t maxsize; 1015166030Spav daddr_t sector; 1016189067Savg int error; 101794663Sscottl 101894663Sscottl bp = a->a_bp; 1019136991Sphk vp = a->a_vp; 102094663Sscottl node = VTON(vp); 102194663Sscottl 1022166030Spav if (bp->b_blkno == bp->b_lblkno) { 1023189067Savg offset = lblktosize(node->udfmp, bp->b_lblkno); 1024189067Savg error = udf_bmap_internal(node, offset, §or, &maxsize); 1025189067Savg if (error) { 102694663Sscottl clrbuf(bp); 102794663Sscottl bp->b_blkno = -1; 1028189067Savg bufdone(bp); 1029189067Savg return (0); 103094663Sscottl } 1031166030Spav /* bmap gives sector numbers, bio works with device blocks */ 1032189067Savg bp->b_blkno = sector << (node->udfmp->bshift - DEV_BSHIFT); 103394663Sscottl } 1034137037Sphk bo = node->udfmp->im_bo; 1035121205Sphk bp->b_iooffset = dbtob(bp->b_blkno); 1036140051Sphk BO_STRATEGY(bo, bp); 103794663Sscottl return (0); 103894663Sscottl} 103994663Sscottl 104094663Sscottlstatic int 104194663Sscottludf_bmap(struct vop_bmap_args *a) 104294663Sscottl{ 104394663Sscottl struct udf_node *node; 104494795Sasmodai uint32_t max_size; 104596572Sphk daddr_t lsector; 1046189070Savg int nblk; 104794663Sscottl int error; 104894663Sscottl 104994663Sscottl node = VTON(a->a_vp); 105094663Sscottl 1051137726Sphk if (a->a_bop != NULL) 1052143668Sphk *a->a_bop = &node->udfmp->im_devvp->v_bufobj; 105394663Sscottl if (a->a_bnp == NULL) 105494663Sscottl return (0); 105594663Sscottl if (a->a_runb) 105694663Sscottl *a->a_runb = 0; 105794663Sscottl 1058189069Savg /* 1059189069Savg * UDF_INVALID_BMAP means data embedded into fentry, this is an internal 1060189069Savg * error that should not be propagated to calling code. 1061189069Savg * Most obvious mapping for this error is EOPNOTSUPP as we can not truly 1062189069Savg * translate block numbers in this case. 1063189069Savg * Incidentally, this return code will make vnode pager to use VOP_READ 1064189069Savg * to get data for mmap-ed pages and udf_read knows how to do the right 1065189069Savg * thing for this kind of files. 1066189069Savg */ 1067189069Savg error = udf_bmap_internal(node, a->a_bn << node->udfmp->bshift, 1068189069Savg &lsector, &max_size); 1069189069Savg if (error == UDF_INVALID_BMAP) 1070189069Savg return (EOPNOTSUPP); 1071101202Sscottl if (error) 107294663Sscottl return (error); 107394663Sscottl 107495913Sscottl /* Translate logical to physical sector number */ 107595913Sscottl *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT); 107695913Sscottl 1077189070Savg /* 1078189070Savg * Determine maximum number of readahead blocks following the 1079189070Savg * requested block. 1080189070Savg */ 1081189070Savg if (a->a_runp) { 1082189070Savg nblk = (max_size >> node->udfmp->bshift) - 1; 1083189070Savg if (nblk <= 0) 1084189070Savg *a->a_runp = 0; 1085189070Savg else if (nblk >= (MAXBSIZE >> node->udfmp->bshift)) 1086189070Savg *a->a_runp = (MAXBSIZE >> node->udfmp->bshift) - 1; 1087189070Savg else 1088189070Savg *a->a_runp = nblk; 1089189070Savg } 109094663Sscottl 1091189070Savg if (a->a_runb) { 1092189070Savg *a->a_runb = 0; 1093189070Savg } 1094189070Savg 109594663Sscottl return (0); 109694663Sscottl} 109794663Sscottl 109894663Sscottl/* 109994663Sscottl * The all powerful VOP_LOOKUP(). 110094663Sscottl */ 110194663Sscottlstatic int 110294663Sscottludf_lookup(struct vop_cachedlookup_args *a) 110394663Sscottl{ 110494663Sscottl struct vnode *dvp; 110594663Sscottl struct vnode *tdp = NULL; 110694663Sscottl struct vnode **vpp = a->a_vpp; 110794663Sscottl struct udf_node *node; 110894663Sscottl struct udf_mnt *udfmp; 110994663Sscottl struct fileid_desc *fid = NULL; 1110101890Sscottl struct udf_dirstream *ds; 111194663Sscottl u_long nameiop; 111294663Sscottl u_long flags; 111394663Sscottl char *nameptr; 111494663Sscottl long namelen; 111594663Sscottl ino_t id = 0; 1116101890Sscottl int offset, error = 0; 1117188407Sjhb int fsize, lkflags, ltype, numdirpasses; 111894663Sscottl 111994663Sscottl dvp = a->a_dvp; 112094663Sscottl node = VTON(dvp); 112194663Sscottl udfmp = node->udfmp; 112294663Sscottl nameiop = a->a_cnp->cn_nameiop; 112394663Sscottl flags = a->a_cnp->cn_flags; 1124188407Sjhb lkflags = a->a_cnp->cn_lkflags; 112594663Sscottl nameptr = a->a_cnp->cn_nameptr; 112694663Sscottl namelen = a->a_cnp->cn_namelen; 1127130994Sscottl fsize = le64toh(node->fentry->inf_len); 112894663Sscottl 112994663Sscottl /* 113094663Sscottl * If this is a LOOKUP and we've already partially searched through 113194663Sscottl * the directory, pick up where we left off and flag that the 113294663Sscottl * directory may need to be searched twice. For a full description, 1133167875Smaxim * see /sys/fs/cd9660/cd9660_lookup.c:cd9660_lookup() 113494663Sscottl */ 1135101890Sscottl if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) { 113694663Sscottl offset = 0; 113794663Sscottl numdirpasses = 1; 113894663Sscottl } else { 113994663Sscottl offset = node->diroff; 114094663Sscottl numdirpasses = 2; 114194663Sscottl nchstats.ncs_2passes++; 114294663Sscottl } 114394663Sscottl 114494663Sscottllookloop: 1145101890Sscottl ds = udf_opendir(node, offset, fsize, udfmp); 114694663Sscottl 1147101890Sscottl while ((fid = udf_getfid(ds)) != NULL) { 114894663Sscottl 1149101890Sscottl /* XXX Should we return an error on a bad fid? */ 1150101890Sscottl if (udf_checktag(&fid->tag, TAGID_FID)) { 1151101890Sscottl printf("udf_lookup: Invalid tag\n"); 1152101890Sscottl error = EIO; 1153101890Sscottl break; 115494663Sscottl } 115594663Sscottl 1156101201Sscottl /* Is this a deleted file? */ 1157101317Sscottl if (fid->file_char & UDF_FILE_CHAR_DEL) 1158101890Sscottl continue; 1159101201Sscottl 1160101317Sscottl if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) { 116194663Sscottl if (flags & ISDOTDOT) { 116294663Sscottl id = udf_getid(&fid->icb); 116394663Sscottl break; 116494663Sscottl } 116594663Sscottl } else { 116694663Sscottl if (!(udf_cmpname(&fid->data[fid->l_iu], 1167122102Sscottl nameptr, fid->l_fi, namelen, udfmp))) { 116894663Sscottl id = udf_getid(&fid->icb); 116994663Sscottl break; 117094663Sscottl } 117194663Sscottl } 1172101890Sscottl } 117394663Sscottl 1174101890Sscottl if (!error) 1175101890Sscottl error = ds->error; 1176101890Sscottl 1177101890Sscottl /* XXX Bail out here? */ 1178101890Sscottl if (error) { 1179101890Sscottl udf_closedir(ds); 1180101890Sscottl return (error); 118194663Sscottl } 118294663Sscottl 118394663Sscottl /* Did we have a match? */ 118494663Sscottl if (id) { 1185188407Sjhb /* 1186188407Sjhb * Remember where this entry was if it's the final 1187188407Sjhb * component. 1188188407Sjhb */ 1189188407Sjhb if ((flags & ISLASTCN) && nameiop == LOOKUP) 1190188407Sjhb node->diroff = ds->offset + ds->off; 1191188407Sjhb if (numdirpasses == 2) 1192188407Sjhb nchstats.ncs_pass2++; 1193188407Sjhb udf_closedir(ds); 1194188407Sjhb 1195188407Sjhb if (flags & ISDOTDOT) { 1196188407Sjhb error = vn_vget_ino(dvp, id, lkflags, &tdp); 1197188407Sjhb } else if (node->hash_id == id) { 1198188407Sjhb VREF(dvp); /* we want ourself, ie "." */ 1199101890Sscottl /* 1200188407Sjhb * When we lookup "." we still can be asked to lock it 1201188407Sjhb * differently. 1202101890Sscottl */ 1203188407Sjhb ltype = lkflags & LK_TYPE_MASK; 1204188407Sjhb if (ltype != VOP_ISLOCKED(dvp)) { 1205188407Sjhb if (ltype == LK_EXCLUSIVE) 1206188407Sjhb vn_lock(dvp, LK_UPGRADE | LK_RETRY); 1207188407Sjhb else /* if (ltype == LK_SHARED) */ 1208188407Sjhb vn_lock(dvp, LK_DOWNGRADE | LK_RETRY); 1209188407Sjhb } 1210188407Sjhb tdp = dvp; 1211188407Sjhb } else 1212188407Sjhb error = udf_vget(udfmp->im_mountp, id, lkflags, &tdp); 1213188407Sjhb if (!error) { 1214101890Sscottl *vpp = tdp; 1215101890Sscottl /* Put this entry in the cache */ 1216101890Sscottl if (flags & MAKEENTRY) 1217101890Sscottl cache_enter(dvp, *vpp, a->a_cnp); 1218145006Sjeff } 1219101890Sscottl } else { 1220101890Sscottl /* Name wasn't found on this pass. Do another pass? */ 1221101890Sscottl if (numdirpasses == 2) { 1222101890Sscottl numdirpasses--; 1223101890Sscottl offset = 0; 1224101890Sscottl udf_closedir(ds); 1225101890Sscottl goto lookloop; 1226101890Sscottl } 1227188407Sjhb udf_closedir(ds); 122894663Sscottl 1229101890Sscottl /* Enter name into cache as non-existant */ 123094663Sscottl if (flags & MAKEENTRY) 123194663Sscottl cache_enter(dvp, *vpp, a->a_cnp); 123294663Sscottl 1233101890Sscottl if ((flags & ISLASTCN) && 1234101890Sscottl (nameiop == CREATE || nameiop == RENAME)) { 1235101890Sscottl error = EROFS; 1236101890Sscottl } else { 1237101890Sscottl error = ENOENT; 1238101890Sscottl } 123994663Sscottl } 124094663Sscottl 1241101890Sscottl return (error); 124294663Sscottl} 124394663Sscottl 124494663Sscottlstatic int 124594663Sscottludf_reclaim(struct vop_reclaim_args *a) 124694663Sscottl{ 124794663Sscottl struct vnode *vp; 124894663Sscottl struct udf_node *unode; 124994663Sscottl 125094663Sscottl vp = a->a_vp; 125194663Sscottl unode = VTON(vp); 125294663Sscottl 1253154487Salfred /* 1254154487Salfred * Destroy the vm object and flush associated pages. 1255154487Salfred */ 1256154487Salfred vnode_destroy_vobject(vp); 1257154487Salfred 125894663Sscottl if (unode != NULL) { 1259143571Sphk vfs_hash_remove(vp); 126094663Sscottl 126194663Sscottl if (unode->fentry != NULL) 1262184205Sdes free(unode->fentry, M_UDFFENTRY); 126394663Sscottl uma_zfree(udf_zone_node, unode); 126494663Sscottl vp->v_data = NULL; 126594663Sscottl } 126694663Sscottl 126794663Sscottl return (0); 126894663Sscottl} 126994663Sscottl 1270166774Spjdstatic int 1271166774Spjdudf_vptofh(struct vop_vptofh_args *a) 1272166774Spjd{ 1273166774Spjd struct udf_node *node; 1274166774Spjd struct ifid *ifhp; 1275166774Spjd 1276166774Spjd node = VTON(a->a_vp); 1277166774Spjd ifhp = (struct ifid *)a->a_fhp; 1278166774Spjd ifhp->ifid_len = sizeof(struct ifid); 1279166774Spjd ifhp->ifid_ino = node->hash_id; 1280166774Spjd 1281166774Spjd return (0); 1282166774Spjd} 1283166774Spjd 128494663Sscottl/* 1285111742Sdes * Read the block and then set the data pointer to correspond with the 128694663Sscottl * offset passed in. Only read in at most 'size' bytes, and then set 'size' 128794663Sscottl * to the number of bytes pointed to. If 'size' is zero, try to read in a 128894663Sscottl * whole extent. 1289127603Sscottl * 1290127603Sscottl * Note that *bp may be assigned error or not. 1291127603Sscottl * 129294663Sscottl */ 129394663Sscottlstatic int 1294140105Sscottludf_readatoffset(struct udf_node *node, int *size, off_t offset, 1295140105Sscottl struct buf **bp, uint8_t **data) 129694663Sscottl{ 1297189082Savg struct udf_mnt *udfmp = node->udfmp; 1298189082Savg struct vnode *vp = node->i_vnode; 1299189082Savg struct file_entry *fentry; 130094663Sscottl struct buf *bp1; 130194795Sasmodai uint32_t max_size; 130296572Sphk daddr_t sector; 1303189082Savg off_t off; 1304189082Savg int adj_size; 130594663Sscottl int error; 130694663Sscottl 1307189082Savg /* 1308189082Savg * This call is made *not* only to detect UDF_INVALID_BMAP case, 1309189082Savg * max_size is used as an ad-hoc read-ahead hint for "normal" case. 1310189082Savg */ 131194663Sscottl error = udf_bmap_internal(node, offset, §or, &max_size); 1312101895Sscottl if (error == UDF_INVALID_BMAP) { 131394663Sscottl /* 131494663Sscottl * This error means that the file *data* is stored in the 131594663Sscottl * allocation descriptor field of the file entry. 131694663Sscottl */ 131794663Sscottl fentry = node->fentry; 1318130994Sscottl *data = &fentry->data[le32toh(fentry->l_ea)]; 1319130994Sscottl *size = le32toh(fentry->l_ad); 1320189111Savg if (offset >= *size) 1321189111Savg *size = 0; 1322189111Savg else { 1323189111Savg *data += offset; 1324189111Savg *size -= offset; 1325189111Savg } 132694663Sscottl return (0); 132794663Sscottl } else if (error != 0) { 132894663Sscottl return (error); 132994663Sscottl } 133094663Sscottl 133195767Sscottl /* Adjust the size so that it is within range */ 133294663Sscottl if (*size == 0 || *size > max_size) 133394663Sscottl *size = max_size; 133494663Sscottl 1335189082Savg /* 1336189082Savg * Because we will read starting at block boundary, we need to adjust 1337189082Savg * how much we need to read so that all promised data is in. 1338189082Savg * Also, we can't promise to read more than MAXBSIZE bytes starting 1339189082Savg * from block boundary, so adjust what we promise too. 1340189082Savg */ 1341189082Savg off = blkoff(udfmp, offset); 1342189082Savg *size = min(*size, MAXBSIZE - off); 1343189082Savg adj_size = (*size + off + udfmp->bmask) & ~udfmp->bmask; 1344189082Savg *bp = NULL; 1345189082Savg if ((error = bread(vp, lblkno(udfmp, offset), adj_size, NOCRED, bp))) { 1346114651Sscottl printf("warning: udf_readlblks returned error %d\n", error); 1347127603Sscottl /* note: *bp may be non-NULL */ 134894663Sscottl return (error); 134994663Sscottl } 135094663Sscottl 135194663Sscottl bp1 = *bp; 1352170577Sremko *data = (uint8_t *)&bp1->b_data[offset & udfmp->bmask]; 135394663Sscottl return (0); 135494663Sscottl} 135594663Sscottl 135694663Sscottl/* 135794663Sscottl * Translate a file offset into a logical block and then into a physical 135894663Sscottl * block. 1359170577Sremko * max_size - maximum number of bytes that can be read starting from given 1360170577Sremko * offset, rather than beginning of calculated sector number 136194663Sscottl */ 136294663Sscottlstatic int 1363140105Sscottludf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector, 1364140105Sscottl uint32_t *max_size) 136594663Sscottl{ 136694663Sscottl struct udf_mnt *udfmp; 136794663Sscottl struct file_entry *fentry; 136894663Sscottl void *icb; 136994663Sscottl struct icb_tag *tag; 137094795Sasmodai uint32_t icblen = 0; 137196572Sphk daddr_t lsector; 137294663Sscottl int ad_offset, ad_num = 0; 137394663Sscottl int i, p_offset; 137494663Sscottl 137594663Sscottl udfmp = node->udfmp; 137694663Sscottl fentry = node->fentry; 137794663Sscottl tag = &fentry->icbtag; 137894663Sscottl 1379130994Sscottl switch (le16toh(tag->strat_type)) { 138094663Sscottl case 4: 138194663Sscottl break; 138294663Sscottl 138394663Sscottl case 4096: 138494663Sscottl printf("Cannot deal with strategy4096 yet!\n"); 138594663Sscottl return (ENODEV); 138694663Sscottl 138794663Sscottl default: 138894663Sscottl printf("Unknown strategy type %d\n", tag->strat_type); 138994663Sscottl return (ENODEV); 139094663Sscottl } 139194663Sscottl 1392130994Sscottl switch (le16toh(tag->flags) & 0x7) { 139394663Sscottl case 0: 139494663Sscottl /* 139594663Sscottl * The allocation descriptor field is filled with short_ad's. 139694663Sscottl * If the offset is beyond the current extent, look for the 139794663Sscottl * next extent. 139894663Sscottl */ 139994663Sscottl do { 140094663Sscottl offset -= icblen; 140194663Sscottl ad_offset = sizeof(struct short_ad) * ad_num; 1402130994Sscottl if (ad_offset > le32toh(fentry->l_ad)) { 140394663Sscottl printf("File offset out of bounds\n"); 140494663Sscottl return (EINVAL); 140594663Sscottl } 1406140416Sscottl icb = GETICB(short_ad, fentry, 1407130994Sscottl le32toh(fentry->l_ea) + ad_offset); 140894663Sscottl icblen = GETICBLEN(short_ad, icb); 140994663Sscottl ad_num++; 141094663Sscottl } while(offset >= icblen); 141194663Sscottl 141294663Sscottl lsector = (offset >> udfmp->bshift) + 1413155256Swill le32toh(((struct short_ad *)(icb))->pos); 141494663Sscottl 1415170577Sremko *max_size = icblen - offset; 141694663Sscottl 141794663Sscottl break; 141894663Sscottl case 1: 141994663Sscottl /* 142094663Sscottl * The allocation descriptor field is filled with long_ad's 142194663Sscottl * If the offset is beyond the current extent, look for the 142294663Sscottl * next extent. 142394663Sscottl */ 142494663Sscottl do { 142594663Sscottl offset -= icblen; 142694663Sscottl ad_offset = sizeof(struct long_ad) * ad_num; 1427130994Sscottl if (ad_offset > le32toh(fentry->l_ad)) { 142894663Sscottl printf("File offset out of bounds\n"); 142994663Sscottl return (EINVAL); 143094663Sscottl } 1431130994Sscottl icb = GETICB(long_ad, fentry, 1432130994Sscottl le32toh(fentry->l_ea) + ad_offset); 143394663Sscottl icblen = GETICBLEN(long_ad, icb); 143494663Sscottl ad_num++; 143594663Sscottl } while(offset >= icblen); 143694663Sscottl 1437111742Sdes lsector = (offset >> udfmp->bshift) + 1438130994Sscottl le32toh(((struct long_ad *)(icb))->loc.lb_num); 143994663Sscottl 1440170577Sremko *max_size = icblen - offset; 144194663Sscottl 144294663Sscottl break; 144394663Sscottl case 3: 144494663Sscottl /* 144594663Sscottl * This type means that the file *data* is stored in the 144694663Sscottl * allocation descriptor field of the file entry. 144794663Sscottl */ 144894663Sscottl *max_size = 0; 1449101202Sscottl *sector = node->hash_id + udfmp->part_start; 145094663Sscottl 1451101895Sscottl return (UDF_INVALID_BMAP); 145294663Sscottl case 2: 145394663Sscottl /* DirectCD does not use extended_ad's */ 145494663Sscottl default: 145594663Sscottl printf("Unsupported allocation descriptor %d\n", 145694663Sscottl tag->flags & 0x7); 145794663Sscottl return (ENODEV); 145894663Sscottl } 145994663Sscottl 146094663Sscottl *sector = lsector + udfmp->part_start; 146194663Sscottl 146294663Sscottl /* 146394663Sscottl * Check the sparing table. Each entry represents the beginning of 146494663Sscottl * a packet. 146594663Sscottl */ 146694663Sscottl if (udfmp->s_table != NULL) { 146794663Sscottl for (i = 0; i< udfmp->s_table_entries; i++) { 1468130994Sscottl p_offset = 1469130994Sscottl lsector - le32toh(udfmp->s_table->entries[i].org); 147094663Sscottl if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) { 1471130994Sscottl *sector = 1472130994Sscottl le32toh(udfmp->s_table->entries[i].map) + 147394663Sscottl p_offset; 147494663Sscottl break; 147594663Sscottl } 147694663Sscottl } 147794663Sscottl } 147894663Sscottl 147994663Sscottl return (0); 148094663Sscottl} 1481