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, §or, &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