[BACK]Return to udf_vnops.c CVS log [TXT][DIR] Up to [local] / sys / isofs / udf

Annotation of sys/isofs/udf/udf_vnops.c, Revision 1.1

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

CVSweb