LCOV - code coverage report
Current view: top level - isofs/udf - udf_vnops.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 642 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13