Annotation of sys/ntfs/ntfs_subr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ntfs_subr.c,v 1.11 2007/06/02 01:02:56 deraadt Exp $ */
! 2: /* $NetBSD: ntfs_subr.c,v 1.4 2003/04/10 21:37:32 jdolecek Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: *
! 29: * Id: ntfs_subr.c,v 1.4 1999/05/12 09:43:01 semenu Exp
! 30: */
! 31:
! 32: #include <sys/cdefs.h>
! 33: #ifdef __KERNEL_RCSID
! 34: __KERNEL_RCSID(0, "$NetBSD: ntfs_subr.c,v 1.4 2003/04/10 21:37:32 jdolecek Exp $");
! 35: #endif
! 36:
! 37: #include <sys/param.h>
! 38: #include <sys/systm.h>
! 39: #include <sys/namei.h>
! 40: #include <sys/proc.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/vnode.h>
! 43: #include <sys/mount.h>
! 44: #include <sys/buf.h>
! 45: #include <sys/file.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/lock.h>
! 48: #if defined(__FreeBSD__)
! 49: #include <machine/clock.h>
! 50: #endif
! 51:
! 52: #include <miscfs/specfs/specdev.h>
! 53:
! 54: /* #define NTFS_DEBUG 1 */
! 55: #if defined(__FreeBSD__) || defined(__NetBSD__)
! 56: #include <fs/ntfs/ntfs.h>
! 57: #include <fs/ntfs/ntfsmount.h>
! 58: #include <fs/ntfs/ntfs_inode.h>
! 59: #include <fs/ntfs/ntfs_vfsops.h>
! 60: #include <fs/ntfs/ntfs_subr.h>
! 61: #include <fs/ntfs/ntfs_compr.h>
! 62: #include <fs/ntfs/ntfs_ihash.h>
! 63: #else
! 64: #include <ntfs/ntfs.h>
! 65: #include <ntfs/ntfsmount.h>
! 66: #include <ntfs/ntfs_inode.h>
! 67: #include <ntfs/ntfs_vfsops.h>
! 68: #include <ntfs/ntfs_subr.h>
! 69: #include <ntfs/ntfs_compr.h>
! 70: #include <ntfs/ntfs_ihash.h>
! 71: #endif
! 72:
! 73: #if defined(NTFS_DEBUG)
! 74: int ntfs_debug = NTFS_DEBUG;
! 75: #endif
! 76:
! 77: #ifdef MALLOC_DEFINE
! 78: MALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information");
! 79: MALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
! 80: MALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
! 81: MALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
! 82: #endif
! 83:
! 84: /* Local struct used in ntfs_ntlookupfile() */
! 85: struct ntfs_lookup_ctx {
! 86: u_int32_t aoff;
! 87: u_int32_t rdsize;
! 88: cn_t cn;
! 89: struct ntfs_lookup_ctx *prev;
! 90: };
! 91:
! 92: static int ntfs_ntlookupattr(struct ntfsmount *, const char *, int, int *, char **);
! 93: static int ntfs_findvattr(struct ntfsmount *, struct ntnode *, struct ntvattr **, struct ntvattr **, u_int32_t, const char *, size_t, cn_t);
! 94: static int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t);
! 95: static int ntfs_uastrcmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t);
! 96:
! 97: /* table for mapping Unicode chars into uppercase; it's filled upon first
! 98: * ntfs mount, freed upon last ntfs umount */
! 99: static wchar *ntfs_toupper_tab;
! 100: #define NTFS_U28(ch) ((((ch) & 0xE0) == 0) ? '_' : (ch) & 0xFF)
! 101: #define NTFS_TOUPPER(ch) (ntfs_toupper_tab[(unsigned char)(ch)])
! 102: static struct lock ntfs_toupper_lock;
! 103: static signed int ntfs_toupper_usecount;
! 104:
! 105: /* support macro for ntfs_ntvattrget() */
! 106: #define NTFS_AALPCMP(aalp,type,name,namelen) ( \
! 107: (aalp->al_type == type) && (aalp->al_namelen == namelen) && \
! 108: !ntfs_uastrcmp(ntmp, aalp->al_name,aalp->al_namelen,name,namelen) )
! 109:
! 110: /*
! 111: *
! 112: */
! 113: int
! 114: ntfs_ntvattrrele(vap)
! 115: struct ntvattr * vap;
! 116: {
! 117: dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
! 118: vap->va_ip->i_number, vap->va_type));
! 119:
! 120: ntfs_ntrele(vap->va_ip);
! 121:
! 122: return (0);
! 123: }
! 124:
! 125: /*
! 126: * find the attribute in the ntnode
! 127: */
! 128: static int
! 129: ntfs_findvattr(ntmp, ip, lvapp, vapp, type, name, namelen, vcn)
! 130: struct ntfsmount *ntmp;
! 131: struct ntnode *ip;
! 132: struct ntvattr **lvapp, **vapp;
! 133: u_int32_t type;
! 134: const char *name;
! 135: size_t namelen;
! 136: cn_t vcn;
! 137: {
! 138: int error;
! 139: struct ntvattr *vap;
! 140:
! 141: if((ip->i_flag & IN_LOADED) == 0) {
! 142: dprintf(("ntfs_findvattr: node not loaded, ino: %d\n",
! 143: ip->i_number));
! 144: error = ntfs_loadntnode(ntmp,ip);
! 145: if (error) {
! 146: printf("ntfs_findvattr: FAILED TO LOAD INO: %d\n",
! 147: ip->i_number);
! 148: return (error);
! 149: }
! 150: }
! 151:
! 152: *lvapp = NULL;
! 153: *vapp = NULL;
! 154: LIST_FOREACH(vap, &ip->i_valist, va_list) {
! 155: ddprintf(("ntfs_findvattr: type: 0x%x, vcn: %d - %d\n", \
! 156: vap->va_type, (u_int32_t) vap->va_vcnstart, \
! 157: (u_int32_t) vap->va_vcnend));
! 158: if ((vap->va_type == type) &&
! 159: (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
! 160: (vap->va_namelen == namelen) &&
! 161: (strncmp(name, vap->va_name, namelen) == 0)) {
! 162: *vapp = vap;
! 163: ntfs_ntref(vap->va_ip);
! 164: return (0);
! 165: }
! 166: if (vap->va_type == NTFS_A_ATTRLIST)
! 167: *lvapp = vap;
! 168: }
! 169:
! 170: return (-1);
! 171: }
! 172:
! 173: /*
! 174: * Search attribute specified in ntnode (load ntnode if necessary).
! 175: * If not found but ATTR_A_ATTRLIST present, read it in and search through.
! 176: * VOP_VGET node needed, and lookup through its ntnode (load if nessesary).
! 177: *
! 178: * ntnode should be locked
! 179: */
! 180: int
! 181: ntfs_ntvattrget(
! 182: struct ntfsmount * ntmp,
! 183: struct ntnode * ip,
! 184: u_int32_t type,
! 185: const char *name,
! 186: cn_t vcn,
! 187: struct ntvattr ** vapp)
! 188: {
! 189: struct ntvattr *lvap = NULL;
! 190: struct attr_attrlist *aalp;
! 191: struct attr_attrlist *nextaalp;
! 192: struct vnode *newvp;
! 193: struct ntnode *newip;
! 194: caddr_t alpool;
! 195: size_t namelen, len;
! 196: int error;
! 197:
! 198: *vapp = NULL;
! 199:
! 200: if (name) {
! 201: dprintf(("ntfs_ntvattrget: " \
! 202: "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
! 203: ip->i_number, type, name, (u_int32_t) vcn));
! 204: namelen = strlen(name);
! 205: } else {
! 206: dprintf(("ntfs_ntvattrget: " \
! 207: "ino: %d, type: 0x%x, vcn: %d\n", \
! 208: ip->i_number, type, (u_int32_t) vcn));
! 209: name = "";
! 210: namelen = 0;
! 211: }
! 212:
! 213: error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn);
! 214: if (error >= 0)
! 215: return (error);
! 216:
! 217: if (!lvap) {
! 218: dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
! 219: "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
! 220: ip->i_number, type, name, (u_int32_t) vcn));
! 221: return (ENOENT);
! 222: }
! 223: /* Scan $ATTRIBUTE_LIST for requested attribute */
! 224: len = lvap->va_datalen;
! 225: alpool = (caddr_t) malloc(len, M_TEMP, M_WAITOK);
! 226: error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len,
! 227: NULL);
! 228: if (error)
! 229: goto out;
! 230:
! 231: aalp = (struct attr_attrlist *) alpool;
! 232: nextaalp = NULL;
! 233:
! 234: for(; len > 0; aalp = nextaalp) {
! 235: dprintf(("ntfs_ntvattrget: " \
! 236: "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
! 237: aalp->al_inumber, aalp->al_type, \
! 238: (u_int32_t) aalp->al_vcnstart));
! 239:
! 240: if (len > aalp->reclen) {
! 241: nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
! 242: } else {
! 243: nextaalp = NULL;
! 244: }
! 245: len -= aalp->reclen;
! 246:
! 247: if (!NTFS_AALPCMP(aalp, type, name, namelen) ||
! 248: (nextaalp && (nextaalp->al_vcnstart <= vcn) &&
! 249: NTFS_AALPCMP(nextaalp, type, name, namelen)))
! 250: continue;
! 251:
! 252: dprintf(("ntfs_ntvattrget: attribute in ino: %d\n",
! 253: aalp->al_inumber));
! 254:
! 255: /* this is not a main record, so we can't use just plain
! 256: vget() */
! 257: error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber,
! 258: NTFS_A_DATA, NULL, LK_EXCLUSIVE,
! 259: VG_EXT, curproc, &newvp);
! 260: if (error) {
! 261: printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
! 262: aalp->al_inumber);
! 263: goto out;
! 264: }
! 265: newip = VTONT(newvp);
! 266: /* XXX have to lock ntnode */
! 267: error = ntfs_findvattr(ntmp, newip, &lvap, vapp,
! 268: type, name, namelen, vcn);
! 269: vput(newvp);
! 270: if (error == 0)
! 271: goto out;
! 272: printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
! 273: break;
! 274: }
! 275: error = ENOENT;
! 276:
! 277: dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
! 278: "ino: %d, type: 0x%x, name: %.*s, vcn: %d\n", \
! 279: ip->i_number, type, (int) namelen, name, (u_int32_t) vcn));
! 280: out:
! 281: free(alpool, M_TEMP);
! 282: return (error);
! 283: }
! 284:
! 285: /*
! 286: * Read ntnode from disk, make ntvattr list.
! 287: *
! 288: * ntnode should be locked
! 289: */
! 290: int
! 291: ntfs_loadntnode(
! 292: struct ntfsmount * ntmp,
! 293: struct ntnode * ip)
! 294: {
! 295: struct filerec *mfrp;
! 296: daddr64_t bn;
! 297: int error,off;
! 298: struct attr *ap;
! 299: struct ntvattr *nvap;
! 300:
! 301: dprintf(("ntfs_loadntnode: loading ino: %d\n",ip->i_number));
! 302:
! 303: mfrp = (struct filerec *) malloc(ntfs_bntob(ntmp->ntm_bpmftrec),
! 304: M_TEMP, M_WAITOK);
! 305:
! 306: if (ip->i_number < NTFS_SYSNODESNUM) {
! 307: struct buf *bp;
! 308:
! 309: dprintf(("ntfs_loadntnode: read system node\n"));
! 310:
! 311: bn = ntfs_cntobn(ntmp->ntm_mftcn) +
! 312: ntmp->ntm_bpmftrec * ip->i_number;
! 313:
! 314: error = bread(ntmp->ntm_devvp,
! 315: bn, ntfs_bntob(ntmp->ntm_bpmftrec),
! 316: NOCRED, &bp);
! 317: if (error) {
! 318: printf("ntfs_loadntnode: BREAD FAILED\n");
! 319: brelse(bp);
! 320: goto out;
! 321: }
! 322: memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
! 323: bqrelse(bp);
! 324: } else {
! 325: struct vnode *vp;
! 326:
! 327: vp = ntmp->ntm_sysvn[NTFS_MFTINO];
! 328: error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
! 329: ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
! 330: ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL);
! 331: if (error) {
! 332: printf("ntfs_loadntnode: ntfs_readattr failed\n");
! 333: goto out;
! 334: }
! 335: }
! 336:
! 337: /* Check if magic and fixups are correct */
! 338: error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
! 339: ntfs_bntob(ntmp->ntm_bpmftrec));
! 340: if (error) {
! 341: printf("ntfs_loadntnode: BAD MFT RECORD %d\n",
! 342: (u_int32_t) ip->i_number);
! 343: goto out;
! 344: }
! 345:
! 346: dprintf(("ntfs_loadntnode: load attrs for ino: %d\n",ip->i_number));
! 347: off = mfrp->fr_attroff;
! 348: ap = (struct attr *) ((caddr_t)mfrp + off);
! 349:
! 350: LIST_INIT(&ip->i_valist);
! 351:
! 352: while (ap->a_hdr.a_type != -1) {
! 353: error = ntfs_attrtontvattr(ntmp, &nvap, ap);
! 354: if (error)
! 355: break;
! 356: nvap->va_ip = ip;
! 357:
! 358: LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
! 359:
! 360: off += ap->a_hdr.reclen;
! 361: ap = (struct attr *) ((caddr_t)mfrp + off);
! 362: }
! 363: if (error) {
! 364: printf("ntfs_loadntnode: failed to load attr ino: %d\n",
! 365: ip->i_number);
! 366: goto out;
! 367: }
! 368:
! 369: ip->i_mainrec = mfrp->fr_mainrec;
! 370: ip->i_nlink = mfrp->fr_nlink;
! 371: ip->i_frflag = mfrp->fr_flags;
! 372:
! 373: ip->i_flag |= IN_LOADED;
! 374:
! 375: out:
! 376: free(mfrp, M_TEMP);
! 377: return (error);
! 378: }
! 379:
! 380: /*
! 381: * Routine locks ntnode and increase usecount, just opposite of
! 382: * ntfs_ntput().
! 383: */
! 384: int
! 385: ntfs_ntget(
! 386: struct ntnode *ip,
! 387: #ifdef __OpenBSD__
! 388: struct proc *p
! 389: #endif
! 390: )
! 391: {
! 392: dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n",
! 393: ip->i_number, ip, ip->i_usecount));
! 394:
! 395: ip->i_usecount++;
! 396:
! 397: lockmgr(&ip->i_lock, LK_EXCLUSIVE, NULL);
! 398:
! 399: return 0;
! 400: }
! 401:
! 402: /*
! 403: * Routine search ntnode in hash, if found: lock, inc usecount and return.
! 404: * If not in hash allocate structure for ntnode, prefill it, lock,
! 405: * inc count and return.
! 406: *
! 407: * ntnode returned locked
! 408: */
! 409: int
! 410: ntfs_ntlookup(
! 411: struct ntfsmount * ntmp,
! 412: ino_t ino,
! 413: #ifndef __OpenBSD__
! 414: struct ntnode ** ipp)
! 415: #else
! 416: struct ntnode ** ipp,
! 417: struct proc * p)
! 418: #endif
! 419: {
! 420: struct ntnode *ip;
! 421:
! 422: dprintf(("ntfs_ntlookup: looking for ntnode %d\n", ino));
! 423:
! 424: do {
! 425: if ((ip = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) {
! 426: #ifndef __OpenBSD__
! 427: ntfs_ntget(ip);
! 428: #else
! 429: ntfs_ntget(ip, p);
! 430: #endif
! 431: dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
! 432: ino, ip, ip->i_usecount));
! 433: *ipp = ip;
! 434: return (0);
! 435: }
! 436: } while (lockmgr(&ntfs_hashlock, LK_EXCLUSIVE | LK_SLEEPFAIL, NULL));
! 437:
! 438: MALLOC(ip, struct ntnode *, sizeof(struct ntnode),
! 439: M_NTFSNTNODE, M_WAITOK);
! 440: ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip));
! 441: bzero((caddr_t) ip, sizeof(struct ntnode));
! 442:
! 443: /* Generic initialization */
! 444: ip->i_devvp = ntmp->ntm_devvp;
! 445: ip->i_dev = ntmp->ntm_dev;
! 446: ip->i_number = ino;
! 447: ip->i_mp = ntmp;
! 448:
! 449: LIST_INIT(&ip->i_fnlist);
! 450: VREF(ip->i_devvp);
! 451:
! 452: /* init lock and lock the newborn ntnode */
! 453: lockinit(&ip->i_lock, PINOD, "ntnode", 0, LK_EXCLUSIVE);
! 454: #ifndef __OpenBSD__
! 455: ntfs_ntget(ip);
! 456: #else
! 457: ntfs_ntget(ip, p);
! 458: #endif
! 459:
! 460: ntfs_nthashins(ip);
! 461:
! 462: lockmgr(&ntfs_hashlock, LK_RELEASE, NULL);
! 463:
! 464: *ipp = ip;
! 465:
! 466: dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
! 467: ino, ip, ip->i_usecount));
! 468:
! 469: return (0);
! 470: }
! 471:
! 472: /*
! 473: * Decrement usecount of ntnode and unlock it, if usecount reach zero,
! 474: * deallocate ntnode.
! 475: *
! 476: * ntnode should be locked on entry, and unlocked on return.
! 477: */
! 478: void
! 479: ntfs_ntput(
! 480: struct ntnode *ip,
! 481: #ifdef __OpenBSD__
! 482: struct proc *p
! 483: #endif
! 484: )
! 485: {
! 486: struct ntvattr *vap;
! 487:
! 488: dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n",
! 489: ip->i_number, ip, ip->i_usecount));
! 490:
! 491: ip->i_usecount--;
! 492:
! 493: #ifdef DIAGNOSTIC
! 494: if (ip->i_usecount < 0) {
! 495: panic("ntfs_ntput: ino: %d usecount: %d ",
! 496: ip->i_number,ip->i_usecount);
! 497: }
! 498: #endif
! 499:
! 500: if (ip->i_usecount > 0) {
! 501: lockmgr(&ip->i_lock, LK_RELEASE, NULL);
! 502: return;
! 503: }
! 504:
! 505: dprintf(("ntfs_ntput: deallocating ntnode: %d\n", ip->i_number));
! 506:
! 507: if (LIST_FIRST(&ip->i_fnlist))
! 508: panic("ntfs_ntput: ntnode has fnodes");
! 509:
! 510: ntfs_nthashrem(ip);
! 511:
! 512: while ((vap = LIST_FIRST(&ip->i_valist)) != NULL) {
! 513: LIST_REMOVE(vap, va_list);
! 514: ntfs_freentvattr(vap);
! 515: }
! 516:
! 517: vrele(ip->i_devvp);
! 518: FREE(ip, M_NTFSNTNODE);
! 519: }
! 520:
! 521: /*
! 522: * increment usecount of ntnode
! 523: */
! 524: void
! 525: ntfs_ntref(ip)
! 526: struct ntnode *ip;
! 527: {
! 528: ip->i_usecount++;
! 529:
! 530: dprintf(("ntfs_ntref: ino %d, usecount: %d\n",
! 531: ip->i_number, ip->i_usecount));
! 532:
! 533: }
! 534:
! 535: /*
! 536: * Decrement usecount of ntnode.
! 537: */
! 538: void
! 539: ntfs_ntrele(ip)
! 540: struct ntnode *ip;
! 541: {
! 542: dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
! 543: ip->i_number, ip, ip->i_usecount));
! 544:
! 545: ip->i_usecount--;
! 546:
! 547: if (ip->i_usecount < 0)
! 548: panic("ntfs_ntrele: ino: %d usecount: %d ",
! 549: ip->i_number,ip->i_usecount);
! 550: }
! 551:
! 552: /*
! 553: * Deallocate all memory allocated for ntvattr
! 554: */
! 555: void
! 556: ntfs_freentvattr(vap)
! 557: struct ntvattr * vap;
! 558: {
! 559: if (vap->va_flag & NTFS_AF_INRUN) {
! 560: if (vap->va_vruncn)
! 561: free(vap->va_vruncn, M_NTFSRUN);
! 562: if (vap->va_vruncl)
! 563: free(vap->va_vruncl, M_NTFSRUN);
! 564: } else {
! 565: if (vap->va_datap)
! 566: free(vap->va_datap, M_NTFSRDATA);
! 567: }
! 568: FREE(vap, M_NTFSNTVATTR);
! 569: }
! 570:
! 571: /*
! 572: * Convert disk image of attribute into ntvattr structure,
! 573: * runs are expanded also.
! 574: */
! 575: int
! 576: ntfs_attrtontvattr(
! 577: struct ntfsmount * ntmp,
! 578: struct ntvattr ** rvapp,
! 579: struct attr * rap)
! 580: {
! 581: int error, i;
! 582: struct ntvattr *vap;
! 583:
! 584: error = 0;
! 585: *rvapp = NULL;
! 586:
! 587: MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr),
! 588: M_NTFSNTVATTR, M_WAITOK);
! 589: bzero(vap, sizeof(struct ntvattr));
! 590: vap->va_ip = NULL;
! 591: vap->va_flag = rap->a_hdr.a_flag;
! 592: vap->va_type = rap->a_hdr.a_type;
! 593: vap->va_compression = rap->a_hdr.a_compression;
! 594: vap->va_index = rap->a_hdr.a_index;
! 595:
! 596: ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
! 597:
! 598: vap->va_namelen = rap->a_hdr.a_namelen;
! 599: if (rap->a_hdr.a_namelen) {
! 600: wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
! 601: ddprintf((", name:["));
! 602: for (i = 0; i < vap->va_namelen; i++) {
! 603: vap->va_name[i] = unp[i];
! 604: ddprintf(("%c", vap->va_name[i]));
! 605: }
! 606: ddprintf(("]"));
! 607: }
! 608: if (vap->va_flag & NTFS_AF_INRUN) {
! 609: ddprintf((", nonres."));
! 610: vap->va_datalen = rap->a_nr.a_datalen;
! 611: vap->va_allocated = rap->a_nr.a_allocated;
! 612: vap->va_vcnstart = rap->a_nr.a_vcnstart;
! 613: vap->va_vcnend = rap->a_nr.a_vcnend;
! 614: vap->va_compressalg = rap->a_nr.a_compressalg;
! 615: error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
! 616: &(vap->va_vruncnt),
! 617: (caddr_t) rap + rap->a_nr.a_dataoff);
! 618: } else {
! 619: vap->va_compressalg = 0;
! 620: ddprintf((", res."));
! 621: vap->va_datalen = rap->a_r.a_datalen;
! 622: vap->va_allocated = rap->a_r.a_datalen;
! 623: vap->va_vcnstart = 0;
! 624: vap->va_vcnend = ntfs_btocn(vap->va_allocated);
! 625: vap->va_datap = (caddr_t) malloc(vap->va_datalen,
! 626: M_NTFSRDATA, M_WAITOK);
! 627: memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
! 628: rap->a_r.a_datalen);
! 629: }
! 630: ddprintf((", len: %d", vap->va_datalen));
! 631:
! 632: if (error)
! 633: FREE(vap, M_NTFSNTVATTR);
! 634: else
! 635: *rvapp = vap;
! 636:
! 637: ddprintf(("\n"));
! 638:
! 639: return (error);
! 640: }
! 641:
! 642: /*
! 643: * Expand run into more utilizable and more memory eating format.
! 644: */
! 645: int
! 646: ntfs_runtovrun(
! 647: cn_t ** rcnp,
! 648: cn_t ** rclp,
! 649: u_long * rcntp,
! 650: u_int8_t * run)
! 651: {
! 652: u_int32_t off;
! 653: u_int32_t sz, i;
! 654: cn_t *cn;
! 655: cn_t *cl;
! 656: u_long cnt;
! 657: cn_t prev;
! 658: cn_t tmp;
! 659:
! 660: off = 0;
! 661: cnt = 0;
! 662: i = 0;
! 663: while (run[off]) {
! 664: off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
! 665: cnt++;
! 666: }
! 667: cn = (cn_t *) malloc(cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
! 668: cl = (cn_t *) malloc(cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
! 669:
! 670: off = 0;
! 671: cnt = 0;
! 672: prev = 0;
! 673: while (run[off]) {
! 674:
! 675: sz = run[off++];
! 676: cl[cnt] = 0;
! 677:
! 678: for (i = 0; i < (sz & 0xF); i++)
! 679: cl[cnt] += (u_int32_t) run[off++] << (i << 3);
! 680:
! 681: sz >>= 4;
! 682: if (run[off + sz - 1] & 0x80) {
! 683: tmp = ((u_int64_t) - 1) << (sz << 3);
! 684: for (i = 0; i < sz; i++)
! 685: tmp |= (u_int64_t) run[off++] << (i << 3);
! 686: } else {
! 687: tmp = 0;
! 688: for (i = 0; i < sz; i++)
! 689: tmp |= (u_int64_t) run[off++] << (i << 3);
! 690: }
! 691: if (tmp)
! 692: prev = cn[cnt] = prev + tmp;
! 693: else
! 694: cn[cnt] = tmp;
! 695:
! 696: cnt++;
! 697: }
! 698: *rcnp = cn;
! 699: *rclp = cl;
! 700: *rcntp = cnt;
! 701: return (0);
! 702: }
! 703:
! 704: /*
! 705: * Compare unicode and ascii string case insens.
! 706: */
! 707: static int
! 708: ntfs_uastricmp(ntmp, ustr, ustrlen, astr, astrlen)
! 709: struct ntfsmount *ntmp;
! 710: const wchar *ustr;
! 711: size_t ustrlen;
! 712: const char *astr;
! 713: size_t astrlen;
! 714: {
! 715: size_t i;
! 716: int res;
! 717: const char *astrend = astr + astrlen;
! 718:
! 719: for (i = 0; i < ustrlen && astr < astrend; i++) {
! 720: res = (*ntmp->ntm_wcmp)(NTFS_TOUPPER(ustr[i]),
! 721: NTFS_TOUPPER((*ntmp->ntm_wget)(&astr)) );
! 722: if (res)
! 723: return res;
! 724: }
! 725:
! 726: if (i == ustrlen && astr == astrend)
! 727: return 0;
! 728: else if (i == ustrlen)
! 729: return -1;
! 730: else
! 731: return 1;
! 732: }
! 733:
! 734: /*
! 735: * Compare unicode and ascii string case sens.
! 736: */
! 737: static int
! 738: ntfs_uastrcmp(ntmp, ustr, ustrlen, astr, astrlen)
! 739: struct ntfsmount *ntmp;
! 740: const wchar *ustr;
! 741: size_t ustrlen;
! 742: const char *astr;
! 743: size_t astrlen;
! 744: {
! 745: size_t i;
! 746: int res;
! 747: const char *astrend = astr + astrlen;
! 748:
! 749: for (i = 0; (i < ustrlen) && (astr < astrend); i++) {
! 750: res = (*ntmp->ntm_wcmp)(ustr[i], (*ntmp->ntm_wget)(&astr));
! 751: if (res)
! 752: return res;
! 753: }
! 754:
! 755: if (i == ustrlen && astr == astrend)
! 756: return 0;
! 757: else if (i == ustrlen)
! 758: return -1;
! 759: else
! 760: return 1;
! 761: }
! 762:
! 763: /*
! 764: * Search fnode in ntnode, if not found allocate and preinitialize.
! 765: *
! 766: * ntnode should be locked on entry.
! 767: */
! 768: int
! 769: ntfs_fget(
! 770: struct ntfsmount *ntmp,
! 771: struct ntnode *ip,
! 772: int attrtype,
! 773: char *attrname,
! 774: struct fnode **fpp)
! 775: {
! 776: struct fnode *fp;
! 777:
! 778: dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
! 779: ip->i_number,attrtype, attrname?attrname:""));
! 780: *fpp = NULL;
! 781: LIST_FOREACH(fp, &ip->i_fnlist, f_fnlist) {
! 782: dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
! 783: fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
! 784:
! 785: if ((attrtype == fp->f_attrtype) &&
! 786: ((!attrname && !fp->f_attrname) ||
! 787: (attrname && fp->f_attrname &&
! 788: !strcmp(attrname,fp->f_attrname)))){
! 789: dprintf(("ntfs_fget: found existed: %p\n",fp));
! 790: *fpp = fp;
! 791: }
! 792: }
! 793:
! 794: if (*fpp)
! 795: return (0);
! 796:
! 797: MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, M_WAITOK);
! 798: bzero(fp, sizeof(struct fnode));
! 799: dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
! 800:
! 801: fp->f_ip = ip;
! 802: fp->f_attrname = attrname;
! 803: if (fp->f_attrname) fp->f_flag |= FN_AATTRNAME;
! 804: fp->f_attrtype = attrtype;
! 805:
! 806: ntfs_ntref(ip);
! 807:
! 808: LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
! 809:
! 810: *fpp = fp;
! 811:
! 812: return (0);
! 813: }
! 814:
! 815: /*
! 816: * Deallocate fnode, remove it from ntnode's fnode list.
! 817: *
! 818: * ntnode should be locked.
! 819: */
! 820: void
! 821: ntfs_frele(
! 822: struct fnode *fp)
! 823: {
! 824: struct ntnode *ip = FTONT(fp);
! 825:
! 826: dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
! 827:
! 828: dprintf(("ntfs_frele: deallocating fnode\n"));
! 829: LIST_REMOVE(fp,f_fnlist);
! 830: if (fp->f_flag & FN_AATTRNAME)
! 831: FREE(fp->f_attrname, M_TEMP);
! 832: if (fp->f_dirblbuf)
! 833: FREE(fp->f_dirblbuf, M_NTFSDIR);
! 834: FREE(fp, M_NTFSFNODE);
! 835: ntfs_ntrele(ip);
! 836: }
! 837:
! 838: /*
! 839: * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME],
! 840: * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
! 841: * If $ATTR_TYPE not specified, ATTR_A_DATA assumed.
! 842: */
! 843: static int
! 844: ntfs_ntlookupattr(
! 845: struct ntfsmount * ntmp,
! 846: const char * name,
! 847: int namelen,
! 848: int *attrtype,
! 849: char **attrname)
! 850: {
! 851: const char *sys;
! 852: size_t syslen, i;
! 853: struct ntvattrdef *adp;
! 854:
! 855: if (namelen == 0)
! 856: return (0);
! 857:
! 858: if (name[0] == '$') {
! 859: sys = name;
! 860: for (syslen = 0; syslen < namelen; syslen++) {
! 861: if(sys[syslen] == ':') {
! 862: name++;
! 863: namelen--;
! 864: break;
! 865: }
! 866: }
! 867: name += syslen;
! 868: namelen -= syslen;
! 869:
! 870: adp = ntmp->ntm_ad;
! 871: for (i = 0; i < ntmp->ntm_adnum; i++, adp++){
! 872: if (syslen != adp->ad_namelen ||
! 873: strncmp(sys, adp->ad_name, syslen) != 0)
! 874: continue;
! 875:
! 876: *attrtype = adp->ad_type;
! 877: goto out;
! 878: }
! 879: return (ENOENT);
! 880: }
! 881:
! 882: out:
! 883: if (namelen) {
! 884: *attrname = (char *) malloc(namelen, M_TEMP, M_WAITOK);
! 885: memcpy((*attrname), name, namelen);
! 886: (*attrname)[namelen] = '\0';
! 887: *attrtype = NTFS_A_DATA;
! 888: }
! 889:
! 890: return (0);
! 891: }
! 892:
! 893: /*
! 894: * Lookup specified node for filename, matching cnp,
! 895: * return fnode filled.
! 896: */
! 897: int
! 898: ntfs_ntlookupfile(
! 899: struct ntfsmount * ntmp,
! 900: struct vnode * vp,
! 901: struct componentname * cnp,
! 902: #ifndef __OpenBSD__
! 903: struct vnode ** vpp)
! 904: #else
! 905: struct vnode ** vpp,
! 906: struct proc *p)
! 907: #endif
! 908: {
! 909: struct fnode *fp = VTOF(vp);
! 910: struct ntnode *ip = FTONT(fp);
! 911: struct ntvattr *vap; /* Root attribute */
! 912: cn_t cn = 0; /* VCN in current attribute */
! 913: caddr_t rdbuf; /* Buffer to read directory's blocks */
! 914: u_int32_t blsize;
! 915: u_int32_t rdsize; /* Length of data to read from current block */
! 916: struct attr_indexentry *iep;
! 917: int error, res, anamelen, fnamelen;
! 918: const char *fname,*aname;
! 919: u_int32_t aoff;
! 920: int attrtype = NTFS_A_DATA;
! 921: char *attrname = NULL;
! 922: struct fnode *nfp;
! 923: struct vnode *nvp;
! 924: enum vtype f_type;
! 925: int fullscan = 0;
! 926: struct ntfs_lookup_ctx *lookup_ctx = NULL, *tctx;
! 927:
! 928: #ifndef __OpenBSD__
! 929: error = ntfs_ntget(ip);
! 930: #else
! 931: error = ntfs_ntget(ip, p);
! 932: #endif
! 933: if (error)
! 934: return (error);
! 935:
! 936: error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
! 937: if (error || (vap->va_flag & NTFS_AF_INRUN))
! 938: return (ENOTDIR);
! 939:
! 940: /*
! 941: * Divide file name into: foofilefoofilefoofile[:attrspec]
! 942: * Store like this: fname:fnamelen [aname:anamelen]
! 943: */
! 944: fname = cnp->cn_nameptr;
! 945: aname = NULL;
! 946: anamelen = 0;
! 947: for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
! 948: if(fname[fnamelen] == ':') {
! 949: aname = fname + fnamelen + 1;
! 950: anamelen = cnp->cn_namelen - fnamelen - 1;
! 951: dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
! 952: fname, fnamelen, aname, anamelen));
! 953: break;
! 954: }
! 955:
! 956: blsize = vap->va_a_iroot->ir_size;
! 957: dprintf(("ntfs_ntlookupfile: blksz: %d\n", blsize));
! 958:
! 959: rdbuf = (caddr_t) malloc(blsize, M_TEMP, M_WAITOK);
! 960:
! 961: loop:
! 962: rdsize = vap->va_datalen;
! 963: dprintf(("ntfs_ntlookupfile: rdsz: %d\n", rdsize));
! 964:
! 965: error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
! 966: 0, rdsize, rdbuf, NULL);
! 967: if (error)
! 968: goto fail;
! 969:
! 970: aoff = sizeof(struct attr_indexroot);
! 971:
! 972: do {
! 973: iep = (struct attr_indexentry *) (rdbuf + aoff);
! 974:
! 975: for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
! 976: aoff += iep->reclen,
! 977: iep = (struct attr_indexentry *) (rdbuf + aoff))
! 978: {
! 979: ddprintf(("scan: %d, %d\n",
! 980: (u_int32_t) iep->ie_number,
! 981: (u_int32_t) iep->ie_fnametype));
! 982:
! 983: /* check the name - the case-insensitive check
! 984: * has to come first, to break from this for loop
! 985: * if needed, so we can dive correctly */
! 986: res = ntfs_uastricmp(ntmp, iep->ie_fname,
! 987: iep->ie_fnamelen, fname, fnamelen);
! 988: if (!fullscan) {
! 989: if (res > 0) break;
! 990: if (res < 0) continue;
! 991: }
! 992:
! 993: if (iep->ie_fnametype == 0 ||
! 994: !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
! 995: {
! 996: res = ntfs_uastrcmp(ntmp, iep->ie_fname,
! 997: iep->ie_fnamelen, fname, fnamelen);
! 998: if (res != 0 && !fullscan) continue;
! 999: }
! 1000:
! 1001: /* if we perform full scan, the file does not match
! 1002: * and this is subnode, dive */
! 1003: if (fullscan && res != 0) {
! 1004: if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
! 1005: MALLOC(tctx, struct ntfs_lookup_ctx *,
! 1006: sizeof(struct ntfs_lookup_ctx),
! 1007: M_TEMP, M_WAITOK);
! 1008: tctx->aoff = aoff + iep->reclen;
! 1009: tctx->rdsize = rdsize;
! 1010: tctx->cn = cn;
! 1011: tctx->prev = lookup_ctx;
! 1012: lookup_ctx = tctx;
! 1013: break;
! 1014: } else
! 1015: continue;
! 1016: }
! 1017:
! 1018: if (aname) {
! 1019: error = ntfs_ntlookupattr(ntmp,
! 1020: aname, anamelen,
! 1021: &attrtype, &attrname);
! 1022: if (error)
! 1023: goto fail;
! 1024: }
! 1025:
! 1026: /* Check if we've found ourselves */
! 1027: if ((iep->ie_number == ip->i_number) &&
! 1028: (attrtype == fp->f_attrtype) &&
! 1029: ((!attrname && !fp->f_attrname) ||
! 1030: (attrname && fp->f_attrname &&
! 1031: !strcmp(attrname, fp->f_attrname))))
! 1032: {
! 1033: VREF(vp);
! 1034: *vpp = vp;
! 1035: error = 0;
! 1036: goto fail;
! 1037: }
! 1038:
! 1039: /* free the buffer returned by ntfs_ntlookupattr() */
! 1040: if (attrname) {
! 1041: FREE(attrname, M_TEMP);
! 1042: attrname = NULL;
! 1043: }
! 1044:
! 1045: /* vget node, but don't load it */
! 1046: error = ntfs_vgetex(ntmp->ntm_mountp,
! 1047: iep->ie_number, attrtype, attrname,
! 1048: LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN,
! 1049: curproc, &nvp);
! 1050: if (error)
! 1051: goto fail;
! 1052:
! 1053: nfp = VTOF(nvp);
! 1054:
! 1055: if (nfp->f_flag & FN_VALID) {
! 1056: *vpp = nvp;
! 1057: goto fail;
! 1058: }
! 1059:
! 1060: nfp->f_fflag = iep->ie_fflag;
! 1061: nfp->f_pnumber = iep->ie_fpnumber;
! 1062: nfp->f_times = iep->ie_ftimes;
! 1063:
! 1064: if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
! 1065: (nfp->f_attrtype == NTFS_A_DATA) &&
! 1066: (nfp->f_attrname == NULL))
! 1067: f_type = VDIR;
! 1068: else
! 1069: f_type = VREG;
! 1070:
! 1071: nvp->v_type = f_type;
! 1072:
! 1073: if ((nfp->f_attrtype == NTFS_A_DATA) &&
! 1074: (nfp->f_attrname == NULL))
! 1075: {
! 1076: /* Opening default attribute */
! 1077: nfp->f_size = iep->ie_fsize;
! 1078: nfp->f_allocated = iep->ie_fallocated;
! 1079: nfp->f_flag |= FN_PRELOADED;
! 1080: } else {
! 1081: error = ntfs_filesize(ntmp, nfp,
! 1082: &nfp->f_size, &nfp->f_allocated);
! 1083: if (error) {
! 1084: vput(nvp);
! 1085: goto fail;
! 1086: }
! 1087: }
! 1088:
! 1089: nfp->f_flag &= ~FN_VALID;
! 1090: *vpp = nvp;
! 1091: goto fail;
! 1092: }
! 1093:
! 1094: /* Dive if possible */
! 1095: if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
! 1096: dprintf(("ntfs_ntlookupfile: diving\n"));
! 1097:
! 1098: cn = *(cn_t *) (rdbuf + aoff +
! 1099: iep->reclen - sizeof(cn_t));
! 1100: rdsize = blsize;
! 1101:
! 1102: error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
! 1103: ntfs_cntob(cn), rdsize, rdbuf, NULL);
! 1104: if (error)
! 1105: goto fail;
! 1106:
! 1107: error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
! 1108: rdbuf, rdsize);
! 1109: if (error)
! 1110: goto fail;
! 1111:
! 1112: aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
! 1113: 0x18);
! 1114: } else if (fullscan && lookup_ctx) {
! 1115: cn = lookup_ctx->cn;
! 1116: aoff = lookup_ctx->aoff;
! 1117: rdsize = lookup_ctx->rdsize;
! 1118:
! 1119: error = ntfs_readattr(ntmp, ip,
! 1120: (cn == 0) ? NTFS_A_INDXROOT : NTFS_A_INDX,
! 1121: "$I30", ntfs_cntob(cn), rdsize, rdbuf, NULL);
! 1122: if (error)
! 1123: goto fail;
! 1124:
! 1125: if (cn != 0) {
! 1126: error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
! 1127: rdbuf, rdsize);
! 1128: if (error)
! 1129: goto fail;
! 1130: }
! 1131:
! 1132: tctx = lookup_ctx;
! 1133: lookup_ctx = lookup_ctx->prev;
! 1134: FREE(tctx, M_TEMP);
! 1135: } else {
! 1136: dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
! 1137: error = ENOENT;
! 1138: break;
! 1139: }
! 1140: } while (1);
! 1141:
! 1142: /* perform full scan if no entry was found */
! 1143: if (!fullscan && error == ENOENT) {
! 1144: fullscan = 1;
! 1145: cn = 0; /* need zero, used by lookup_ctx */
! 1146:
! 1147: ddprintf(("ntfs_ntlookupfile: fullscan performed for: %.*s\n",
! 1148: (int) fnamelen, fname));
! 1149: goto loop;
! 1150: }
! 1151:
! 1152: dprintf(("finish\n"));
! 1153:
! 1154: fail:
! 1155: if (attrname)
! 1156: FREE(attrname, M_TEMP);
! 1157: if (lookup_ctx) {
! 1158: while(lookup_ctx) {
! 1159: tctx = lookup_ctx;
! 1160: lookup_ctx = lookup_ctx->prev;
! 1161: FREE(tctx, M_TEMP);
! 1162: }
! 1163: }
! 1164: ntfs_ntvattrrele(vap);
! 1165: #ifndef __OpenBSD__
! 1166: ntfs_ntput(ip);
! 1167: #else
! 1168: ntfs_ntput(ip, p);
! 1169: #endif
! 1170: free(rdbuf, M_TEMP);
! 1171: return (error);
! 1172: }
! 1173:
! 1174: /*
! 1175: * Check if name type is permitted to show.
! 1176: */
! 1177: int
! 1178: ntfs_isnamepermitted(
! 1179: struct ntfsmount * ntmp,
! 1180: struct attr_indexentry * iep)
! 1181: {
! 1182: if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
! 1183: return 1;
! 1184:
! 1185: switch (iep->ie_fnametype) {
! 1186: case 2:
! 1187: ddprintf(("ntfs_isnamepermitted: skipped DOS name\n"));
! 1188: return 0;
! 1189: case 0: case 1: case 3:
! 1190: return 1;
! 1191: default:
! 1192: printf("ntfs_isnamepermitted: " \
! 1193: "WARNING! Unknown file name type: %d\n",
! 1194: iep->ie_fnametype);
! 1195: break;
! 1196: }
! 1197: return 0;
! 1198: }
! 1199:
! 1200: /*
! 1201: * Read ntfs dir like stream of attr_indexentry, not like btree of them.
! 1202: * This is done by scanning $BITMAP:$I30 for busy clusters and reading them.
! 1203: * Of course $INDEX_ROOT:$I30 is read before. Last read values are stored in
! 1204: * fnode, so we can skip toward record number num almost immediately.
! 1205: * Anyway this is rather slow routine. The problem is that we don't know
! 1206: * how many records are there in $INDEX_ALLOCATION:$I30 block.
! 1207: */
! 1208: int
! 1209: ntfs_ntreaddir(
! 1210: struct ntfsmount * ntmp,
! 1211: struct fnode * fp,
! 1212: u_int32_t num,
! 1213: #ifndef __OpenBSD__
! 1214: struct attr_indexentry ** riepp)
! 1215: #else
! 1216: struct attr_indexentry ** riepp,
! 1217: struct proc *p)
! 1218: #endif
! 1219: {
! 1220: struct ntnode *ip = FTONT(fp);
! 1221: struct ntvattr *vap = NULL; /* IndexRoot attribute */
! 1222: struct ntvattr *bmvap = NULL; /* BitMap attribute */
! 1223: struct ntvattr *iavap = NULL; /* IndexAllocation attribute */
! 1224: caddr_t rdbuf; /* Buffer to read directory's blocks */
! 1225: u_int8_t *bmp = NULL; /* Bitmap */
! 1226: u_int32_t blsize; /* Index allocation size (2048) */
! 1227: u_int32_t rdsize; /* Length of data to read */
! 1228: u_int32_t attrnum; /* Current attribute type */
! 1229: u_int32_t cpbl = 1; /* Clusters per directory block */
! 1230: u_int32_t blnum;
! 1231: struct attr_indexentry *iep;
! 1232: int error = ENOENT;
! 1233: u_int32_t aoff, cnum;
! 1234:
! 1235: dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
! 1236: #ifndef __OpenBSD__
! 1237: error = ntfs_ntget(ip);
! 1238: #else
! 1239: error = ntfs_ntget(ip, p);
! 1240: #endif
! 1241: if (error)
! 1242: return (error);
! 1243:
! 1244: error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
! 1245: if (error)
! 1246: return (ENOTDIR);
! 1247:
! 1248: if (fp->f_dirblbuf == NULL) {
! 1249: fp->f_dirblsz = vap->va_a_iroot->ir_size;
! 1250: fp->f_dirblbuf = (caddr_t) malloc(
! 1251: MAX(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
! 1252: }
! 1253:
! 1254: blsize = fp->f_dirblsz;
! 1255: rdbuf = fp->f_dirblbuf;
! 1256:
! 1257: dprintf(("ntfs_ntreaddir: rdbuf: %p, blsize: %d\n", rdbuf, blsize));
! 1258:
! 1259: if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
! 1260: error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
! 1261: 0, &bmvap);
! 1262: if (error) {
! 1263: error = ENOTDIR;
! 1264: goto fail;
! 1265: }
! 1266: bmp = (u_int8_t *) malloc(bmvap->va_datalen, M_TEMP, M_WAITOK);
! 1267: error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
! 1268: bmvap->va_datalen, bmp, NULL);
! 1269: if (error)
! 1270: goto fail;
! 1271:
! 1272: error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
! 1273: 0, &iavap);
! 1274: if (error) {
! 1275: error = ENOTDIR;
! 1276: goto fail;
! 1277: }
! 1278: cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
! 1279: dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
! 1280: iavap->va_datalen, cpbl));
! 1281: } else {
! 1282: dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
! 1283: iavap = bmvap = NULL;
! 1284: bmp = NULL;
! 1285: }
! 1286:
! 1287: /* Try use previous values */
! 1288: if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
! 1289: attrnum = fp->f_lastdattr;
! 1290: aoff = fp->f_lastdoff;
! 1291: blnum = fp->f_lastdblnum;
! 1292: cnum = fp->f_lastdnum;
! 1293: } else {
! 1294: attrnum = NTFS_A_INDXROOT;
! 1295: aoff = sizeof(struct attr_indexroot);
! 1296: blnum = 0;
! 1297: cnum = 0;
! 1298: }
! 1299:
! 1300: do {
! 1301: dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
! 1302: attrnum, (u_int32_t) blnum, cnum, num, aoff));
! 1303: rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
! 1304: error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
! 1305: ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
! 1306: if (error)
! 1307: goto fail;
! 1308:
! 1309: if (attrnum == NTFS_A_INDX) {
! 1310: error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
! 1311: rdbuf, rdsize);
! 1312: if (error)
! 1313: goto fail;
! 1314: }
! 1315: if (aoff == 0)
! 1316: aoff = (attrnum == NTFS_A_INDX) ?
! 1317: (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
! 1318: sizeof(struct attr_indexroot);
! 1319:
! 1320: iep = (struct attr_indexentry *) (rdbuf + aoff);
! 1321: for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
! 1322: aoff += iep->reclen,
! 1323: iep = (struct attr_indexentry *) (rdbuf + aoff))
! 1324: {
! 1325: if (!ntfs_isnamepermitted(ntmp, iep)) continue;
! 1326:
! 1327: if (cnum >= num) {
! 1328: fp->f_lastdnum = cnum;
! 1329: fp->f_lastdoff = aoff;
! 1330: fp->f_lastdblnum = blnum;
! 1331: fp->f_lastdattr = attrnum;
! 1332:
! 1333: *riepp = iep;
! 1334:
! 1335: error = 0;
! 1336: goto fail;
! 1337: }
! 1338: cnum++;
! 1339: }
! 1340:
! 1341: if (iavap) {
! 1342: if (attrnum == NTFS_A_INDXROOT)
! 1343: blnum = 0;
! 1344: else
! 1345: blnum++;
! 1346:
! 1347: while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
! 1348: if (bmp[blnum >> 3] & (1 << (blnum & 7)))
! 1349: break;
! 1350: blnum++;
! 1351: }
! 1352:
! 1353: attrnum = NTFS_A_INDX;
! 1354: aoff = 0;
! 1355: if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
! 1356: break;
! 1357: dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
! 1358: }
! 1359: } while (iavap);
! 1360:
! 1361: *riepp = NULL;
! 1362: fp->f_lastdnum = 0;
! 1363:
! 1364: fail:
! 1365: if (vap)
! 1366: ntfs_ntvattrrele(vap);
! 1367: if (bmvap)
! 1368: ntfs_ntvattrrele(bmvap);
! 1369: if (iavap)
! 1370: ntfs_ntvattrrele(iavap);
! 1371: if (bmp)
! 1372: FREE(bmp, M_TEMP);
! 1373: #ifndef __OpenBSD__
! 1374: ntfs_ntput(ip);
! 1375: #else
! 1376: ntfs_ntput(ip, p);
! 1377: #endif
! 1378: return (error);
! 1379: }
! 1380:
! 1381: /*
! 1382: * Convert NTFS times that are in 100 ns units and begins from
! 1383: * 1601 Jan 1 into unix times.
! 1384: */
! 1385: struct timespec
! 1386: ntfs_nttimetounix(
! 1387: u_int64_t nt)
! 1388: {
! 1389: struct timespec t;
! 1390:
! 1391: /* WindowNT times are in 100 ns and from 1601 Jan 1 */
! 1392: t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
! 1393: t.tv_sec = nt / (1000 * 1000 * 10) -
! 1394: 369LL * 365LL * 24LL * 60LL * 60LL -
! 1395: 89LL * 1LL * 24LL * 60LL * 60LL;
! 1396: return (t);
! 1397: }
! 1398:
! 1399: #ifndef __OpenBSD__
! 1400: /*
! 1401: * Get file times from NTFS_A_NAME attribute.
! 1402: */
! 1403: int
! 1404: ntfs_times(
! 1405: struct ntfsmount * ntmp,
! 1406: struct ntnode * ip,
! 1407: ntfs_times_t * tm)
! 1408: {
! 1409: struct ntvattr *vap;
! 1410: int error;
! 1411:
! 1412: dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
! 1413:
! 1414: error = ntfs_ntget(ip);
! 1415: if (error)
! 1416: return (error);
! 1417:
! 1418: error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
! 1419: if (error) {
! 1420: ntfs_ntput(ip);
! 1421: return (error);
! 1422: }
! 1423: *tm = vap->va_a_name->n_times;
! 1424: ntfs_ntvattrrele(vap);
! 1425: ntfs_ntput(ip);
! 1426:
! 1427: return (0);
! 1428: }
! 1429: #endif
! 1430:
! 1431: /*
! 1432: * Get file sizes from corresponding attribute.
! 1433: *
! 1434: * ntnode under fnode should be locked.
! 1435: */
! 1436: int
! 1437: ntfs_filesize(
! 1438: struct ntfsmount * ntmp,
! 1439: struct fnode * fp,
! 1440: u_int64_t * size,
! 1441: u_int64_t * bytes)
! 1442: {
! 1443: struct ntvattr *vap;
! 1444: struct ntnode *ip = FTONT(fp);
! 1445: u_int64_t sz, bn;
! 1446: int error;
! 1447:
! 1448: dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
! 1449:
! 1450: error = ntfs_ntvattrget(ntmp, ip,
! 1451: fp->f_attrtype, fp->f_attrname, 0, &vap);
! 1452: if (error)
! 1453: return (error);
! 1454:
! 1455: bn = vap->va_allocated;
! 1456: sz = vap->va_datalen;
! 1457:
! 1458: dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
! 1459: (u_int32_t) sz, (u_int32_t) bn));
! 1460:
! 1461: if (size)
! 1462: *size = sz;
! 1463: if (bytes)
! 1464: *bytes = bn;
! 1465:
! 1466: ntfs_ntvattrrele(vap);
! 1467:
! 1468: return (0);
! 1469: }
! 1470:
! 1471: /*
! 1472: * This is one of the write routines.
! 1473: */
! 1474: int
! 1475: ntfs_writeattr_plain(
! 1476: struct ntfsmount * ntmp,
! 1477: struct ntnode * ip,
! 1478: u_int32_t attrnum,
! 1479: char *attrname,
! 1480: off_t roff,
! 1481: size_t rsize,
! 1482: void *rdata,
! 1483: size_t * initp,
! 1484: struct uio *uio)
! 1485: {
! 1486: size_t init;
! 1487: int error = 0;
! 1488: off_t off = roff, left = rsize, towrite;
! 1489: caddr_t data = rdata;
! 1490: struct ntvattr *vap;
! 1491: *initp = 0;
! 1492:
! 1493: while (left) {
! 1494: error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
! 1495: ntfs_btocn(off), &vap);
! 1496: if (error)
! 1497: return (error);
! 1498: towrite = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
! 1499: ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
! 1500: (u_int32_t) off, (u_int32_t) towrite,
! 1501: (u_int32_t) vap->va_vcnstart,
! 1502: (u_int32_t) vap->va_vcnend));
! 1503: error = ntfs_writentvattr_plain(ntmp, ip, vap,
! 1504: off - ntfs_cntob(vap->va_vcnstart),
! 1505: towrite, data, &init, uio);
! 1506: if (error) {
! 1507: dprintf(("ntfs_writeattr_plain: " \
! 1508: "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
! 1509: (u_int32_t) off, (u_int32_t) towrite));
! 1510: dprintf(("ntfs_writeattr_plain: attrib: %d - %d\n",
! 1511: (u_int32_t) vap->va_vcnstart,
! 1512: (u_int32_t) vap->va_vcnend));
! 1513: ntfs_ntvattrrele(vap);
! 1514: break;
! 1515: }
! 1516: ntfs_ntvattrrele(vap);
! 1517: left -= towrite;
! 1518: off += towrite;
! 1519: data = data + towrite;
! 1520: *initp += init;
! 1521: }
! 1522:
! 1523: return (error);
! 1524: }
! 1525:
! 1526: /*
! 1527: * This is one of the write routines.
! 1528: *
! 1529: * ntnode should be locked.
! 1530: */
! 1531: int
! 1532: ntfs_writentvattr_plain(
! 1533: struct ntfsmount * ntmp,
! 1534: struct ntnode * ip,
! 1535: struct ntvattr * vap,
! 1536: off_t roff,
! 1537: size_t rsize,
! 1538: void *rdata,
! 1539: size_t * initp,
! 1540: struct uio *uio)
! 1541: {
! 1542: int error = 0;
! 1543: int off;
! 1544: int cnt;
! 1545: cn_t ccn, ccl, cn, left, cl;
! 1546: caddr_t data = rdata;
! 1547: struct buf *bp;
! 1548: size_t tocopy;
! 1549:
! 1550: *initp = 0;
! 1551:
! 1552: if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
! 1553: dprintf(("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n"));
! 1554: return ENOTTY;
! 1555: }
! 1556:
! 1557: ddprintf(("ntfs_writentvattr_plain: data in run: %lu chains\n",
! 1558: vap->va_vruncnt));
! 1559:
! 1560: off = roff;
! 1561: left = rsize;
! 1562: ccl = 0;
! 1563: ccn = 0;
! 1564: cnt = 0;
! 1565: for (; left && (cnt < vap->va_vruncnt); cnt++) {
! 1566: ccn = vap->va_vruncn[cnt];
! 1567: ccl = vap->va_vruncl[cnt];
! 1568:
! 1569: ddprintf(("ntfs_writentvattr_plain: " \
! 1570: "left %d, cn: 0x%x, cl: %d, off: %d\n", \
! 1571: (u_int32_t) left, (u_int32_t) ccn, \
! 1572: (u_int32_t) ccl, (u_int32_t) off));
! 1573:
! 1574: if (ntfs_cntob(ccl) < off) {
! 1575: off -= ntfs_cntob(ccl);
! 1576: cnt++;
! 1577: continue;
! 1578: }
! 1579: if (!ccn && ip->i_number != NTFS_BOOTINO)
! 1580: continue; /* XXX */
! 1581:
! 1582: ccl -= ntfs_btocn(off);
! 1583: cn = ccn + ntfs_btocn(off);
! 1584: off = ntfs_btocnoff(off);
! 1585:
! 1586: while (left && ccl) {
! 1587: /*
! 1588: * Always read and write single clusters at a time -
! 1589: * we need to avoid requesting differently-sized
! 1590: * blocks at the same disk offsets to avoid
! 1591: * confusing the buffer cache.
! 1592: */
! 1593: tocopy = MIN(left, ntfs_cntob(1) - off);
! 1594: cl = ntfs_btocl(tocopy + off);
! 1595: KASSERT(cl == 1 && tocopy <= ntfs_cntob(1));
! 1596: ddprintf(("ntfs_writentvattr_plain: write: " \
! 1597: "cn: 0x%x cl: %d, off: %d len: %d, left: %d\n",
! 1598: (u_int32_t) cn, (u_int32_t) cl,
! 1599: (u_int32_t) off, (u_int32_t) tocopy,
! 1600: (u_int32_t) left));
! 1601: if ((off == 0) && (tocopy == ntfs_cntob(cl)))
! 1602: {
! 1603: bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn),
! 1604: ntfs_cntob(cl), 0, 0);
! 1605: clrbuf(bp);
! 1606: } else {
! 1607: error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn),
! 1608: ntfs_cntob(cl), NOCRED, &bp);
! 1609: if (error) {
! 1610: brelse(bp);
! 1611: return (error);
! 1612: }
! 1613: }
! 1614: if (uio)
! 1615: uiomove(bp->b_data + off, tocopy, uio);
! 1616: else
! 1617: memcpy(bp->b_data + off, data, tocopy);
! 1618: bawrite(bp);
! 1619: data = data + tocopy;
! 1620: *initp += tocopy;
! 1621: off = 0;
! 1622: left -= tocopy;
! 1623: cn += cl;
! 1624: ccl -= cl;
! 1625: }
! 1626: }
! 1627:
! 1628: if (left) {
! 1629: printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
! 1630: error = EINVAL;
! 1631: }
! 1632:
! 1633: return (error);
! 1634: }
! 1635:
! 1636: /*
! 1637: * This is one of the read routines.
! 1638: *
! 1639: * ntnode should be locked.
! 1640: */
! 1641: int
! 1642: ntfs_readntvattr_plain(
! 1643: struct ntfsmount * ntmp,
! 1644: struct ntnode * ip,
! 1645: struct ntvattr * vap,
! 1646: off_t roff,
! 1647: size_t rsize,
! 1648: void *rdata,
! 1649: size_t * initp,
! 1650: struct uio *uio)
! 1651: {
! 1652: int error = 0;
! 1653: int off;
! 1654:
! 1655: *initp = 0;
! 1656: if (vap->va_flag & NTFS_AF_INRUN) {
! 1657: int cnt;
! 1658: cn_t ccn, ccl, cn, left, cl;
! 1659: caddr_t data = rdata;
! 1660: struct buf *bp;
! 1661: size_t tocopy;
! 1662:
! 1663: ddprintf(("ntfs_readntvattr_plain: data in run: %lu chains\n",
! 1664: vap->va_vruncnt));
! 1665:
! 1666: off = roff;
! 1667: left = rsize;
! 1668: ccl = 0;
! 1669: ccn = 0;
! 1670: cnt = 0;
! 1671: while (left && (cnt < vap->va_vruncnt)) {
! 1672: ccn = vap->va_vruncn[cnt];
! 1673: ccl = vap->va_vruncl[cnt];
! 1674:
! 1675: ddprintf(("ntfs_readntvattr_plain: " \
! 1676: "left %d, cn: 0x%x, cl: %d, off: %d\n", \
! 1677: (u_int32_t) left, (u_int32_t) ccn, \
! 1678: (u_int32_t) ccl, (u_int32_t) off));
! 1679:
! 1680: if (ntfs_cntob(ccl) < off) {
! 1681: off -= ntfs_cntob(ccl);
! 1682: cnt++;
! 1683: continue;
! 1684: }
! 1685: if (ccn || ip->i_number == NTFS_BOOTINO) {
! 1686: ccl -= ntfs_btocn(off);
! 1687: cn = ccn + ntfs_btocn(off);
! 1688: off = ntfs_btocnoff(off);
! 1689:
! 1690: while (left && ccl) {
! 1691: /*
! 1692: * Always read single clusters at a
! 1693: * time - we need to avoid reading
! 1694: * differently-sized blocks at the
! 1695: * same disk offsets to avoid
! 1696: * confusing the buffer cache.
! 1697: */
! 1698: tocopy = MIN(left,
! 1699: ntfs_cntob(1) - off);
! 1700: cl = ntfs_btocl(tocopy + off);
! 1701: KASSERT(cl == 1 &&
! 1702: tocopy <= ntfs_cntob(1));
! 1703:
! 1704: ddprintf(("ntfs_readntvattr_plain: " \
! 1705: "read: cn: 0x%x cl: %d, " \
! 1706: "off: %d len: %d, left: %d\n",
! 1707: (u_int32_t) cn,
! 1708: (u_int32_t) cl,
! 1709: (u_int32_t) off,
! 1710: (u_int32_t) tocopy,
! 1711: (u_int32_t) left));
! 1712: error = bread(ntmp->ntm_devvp,
! 1713: ntfs_cntobn(cn),
! 1714: ntfs_cntob(cl),
! 1715: NOCRED, &bp);
! 1716: if (error) {
! 1717: brelse(bp);
! 1718: return (error);
! 1719: }
! 1720: if (uio) {
! 1721: uiomove(bp->b_data + off,
! 1722: tocopy, uio);
! 1723: } else {
! 1724: memcpy(data, bp->b_data + off,
! 1725: tocopy);
! 1726: }
! 1727: brelse(bp);
! 1728: data = data + tocopy;
! 1729: *initp += tocopy;
! 1730: off = 0;
! 1731: left -= tocopy;
! 1732: cn += cl;
! 1733: ccl -= cl;
! 1734: }
! 1735: } else {
! 1736: tocopy = MIN(left, ntfs_cntob(ccl) - off);
! 1737: ddprintf(("ntfs_readntvattr_plain: "
! 1738: "hole: ccn: 0x%x ccl: %d, off: %d, " \
! 1739: " len: %d, left: %d\n",
! 1740: (u_int32_t) ccn, (u_int32_t) ccl,
! 1741: (u_int32_t) off, (u_int32_t) tocopy,
! 1742: (u_int32_t) left));
! 1743: left -= tocopy;
! 1744: off = 0;
! 1745: if (uio) {
! 1746: size_t remains = tocopy;
! 1747: for(; remains; remains--)
! 1748: uiomove("", 1, uio);
! 1749: } else
! 1750: bzero(data, tocopy);
! 1751: data = data + tocopy;
! 1752: }
! 1753: cnt++;
! 1754: }
! 1755: if (left) {
! 1756: printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
! 1757: error = E2BIG;
! 1758: }
! 1759: } else {
! 1760: ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
! 1761: if (uio)
! 1762: uiomove(vap->va_datap + roff, rsize, uio);
! 1763: else
! 1764: memcpy(rdata, vap->va_datap + roff, rsize);
! 1765: *initp += rsize;
! 1766: }
! 1767:
! 1768: return (error);
! 1769: }
! 1770:
! 1771: /*
! 1772: * This is one of read routines.
! 1773: */
! 1774: int
! 1775: ntfs_readattr_plain(
! 1776: struct ntfsmount * ntmp,
! 1777: struct ntnode * ip,
! 1778: u_int32_t attrnum,
! 1779: char *attrname,
! 1780: off_t roff,
! 1781: size_t rsize,
! 1782: void *rdata,
! 1783: size_t * initp,
! 1784: struct uio *uio)
! 1785: {
! 1786: size_t init;
! 1787: int error = 0;
! 1788: off_t off = roff, left = rsize, toread;
! 1789: caddr_t data = rdata;
! 1790: struct ntvattr *vap;
! 1791: *initp = 0;
! 1792:
! 1793: while (left) {
! 1794: error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
! 1795: ntfs_btocn(off), &vap);
! 1796: if (error)
! 1797: return (error);
! 1798: toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
! 1799: ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
! 1800: (u_int32_t) off, (u_int32_t) toread,
! 1801: (u_int32_t) vap->va_vcnstart,
! 1802: (u_int32_t) vap->va_vcnend));
! 1803: error = ntfs_readntvattr_plain(ntmp, ip, vap,
! 1804: off - ntfs_cntob(vap->va_vcnstart),
! 1805: toread, data, &init, uio);
! 1806: if (error) {
! 1807: printf("ntfs_readattr_plain: " \
! 1808: "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
! 1809: (u_int32_t) off, (u_int32_t) toread);
! 1810: printf("ntfs_readattr_plain: attrib: %d - %d\n",
! 1811: (u_int32_t) vap->va_vcnstart,
! 1812: (u_int32_t) vap->va_vcnend);
! 1813: ntfs_ntvattrrele(vap);
! 1814: break;
! 1815: }
! 1816: ntfs_ntvattrrele(vap);
! 1817: left -= toread;
! 1818: off += toread;
! 1819: data = data + toread;
! 1820: *initp += init;
! 1821: }
! 1822:
! 1823: return (error);
! 1824: }
! 1825:
! 1826: /*
! 1827: * This is one of read routines.
! 1828: */
! 1829: int
! 1830: ntfs_readattr(
! 1831: struct ntfsmount * ntmp,
! 1832: struct ntnode * ip,
! 1833: u_int32_t attrnum,
! 1834: char *attrname,
! 1835: off_t roff,
! 1836: size_t rsize,
! 1837: void *rdata,
! 1838: struct uio *uio)
! 1839: {
! 1840: int error = 0;
! 1841: struct ntvattr *vap;
! 1842: size_t init;
! 1843:
! 1844: ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
! 1845: ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
! 1846:
! 1847: error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
! 1848: if (error)
! 1849: return (error);
! 1850:
! 1851: if ((roff > vap->va_datalen) ||
! 1852: (roff + rsize > vap->va_datalen)) {
! 1853: printf("ntfs_readattr: offset too big: %ld (%ld) > %ld\n",
! 1854: (long int) roff, (long int) roff + rsize,
! 1855: (long int) vap->va_datalen);
! 1856: ntfs_ntvattrrele(vap);
! 1857: return (E2BIG);
! 1858: }
! 1859: if (vap->va_compression && vap->va_compressalg) {
! 1860: u_int8_t *cup;
! 1861: u_int8_t *uup;
! 1862: off_t off = roff, left = rsize, tocopy;
! 1863: caddr_t data = rdata;
! 1864: cn_t cn;
! 1865:
! 1866: ddprintf(("ntfs_ntreadattr: compression: %d\n",
! 1867: vap->va_compressalg));
! 1868:
! 1869: MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
! 1870: M_NTFSDECOMP, M_WAITOK);
! 1871: MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
! 1872: M_NTFSDECOMP, M_WAITOK);
! 1873:
! 1874: cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
! 1875: off = roff - ntfs_cntob(cn);
! 1876:
! 1877: while (left) {
! 1878: error = ntfs_readattr_plain(ntmp, ip, attrnum,
! 1879: attrname, ntfs_cntob(cn),
! 1880: ntfs_cntob(NTFS_COMPUNIT_CL),
! 1881: cup, &init, NULL);
! 1882: if (error)
! 1883: break;
! 1884:
! 1885: tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
! 1886:
! 1887: if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
! 1888: if (uio)
! 1889: uiomove(cup + off, tocopy, uio);
! 1890: else
! 1891: memcpy(data, cup + off, tocopy);
! 1892: } else if (init == 0) {
! 1893: if (uio) {
! 1894: size_t remains = tocopy;
! 1895: for(; remains; remains--)
! 1896: uiomove("", 1, uio);
! 1897: }
! 1898: else
! 1899: bzero(data, tocopy);
! 1900: } else {
! 1901: error = ntfs_uncompunit(ntmp, uup, cup);
! 1902: if (error)
! 1903: break;
! 1904: if (uio)
! 1905: uiomove(uup + off, tocopy, uio);
! 1906: else
! 1907: memcpy(data, uup + off, tocopy);
! 1908: }
! 1909:
! 1910: left -= tocopy;
! 1911: data = data + tocopy;
! 1912: off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
! 1913: cn += NTFS_COMPUNIT_CL;
! 1914: }
! 1915:
! 1916: FREE(uup, M_NTFSDECOMP);
! 1917: FREE(cup, M_NTFSDECOMP);
! 1918: } else
! 1919: error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
! 1920: roff, rsize, rdata, &init, uio);
! 1921: ntfs_ntvattrrele(vap);
! 1922: return (error);
! 1923: }
! 1924:
! 1925: #if UNUSED_CODE
! 1926: int
! 1927: ntfs_parserun(
! 1928: cn_t * cn,
! 1929: cn_t * cl,
! 1930: u_int8_t * run,
! 1931: u_long len,
! 1932: u_long *off)
! 1933: {
! 1934: u_int8_t sz;
! 1935: int i;
! 1936:
! 1937: if (NULL == run) {
! 1938: printf("ntfs_parsetun: run == NULL\n");
! 1939: return (EINVAL);
! 1940: }
! 1941: sz = run[(*off)++];
! 1942: if (0 == sz) {
! 1943: printf("ntfs_parserun: trying to go out of run\n");
! 1944: return (E2BIG);
! 1945: }
! 1946: *cl = 0;
! 1947: if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
! 1948: printf("ntfs_parserun: " \
! 1949: "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
! 1950: sz, len, *off);
! 1951: return (EINVAL);
! 1952: }
! 1953: for (i = 0; i < (sz & 0xF); i++)
! 1954: *cl += (u_int32_t) run[(*off)++] << (i << 3);
! 1955:
! 1956: sz >>= 4;
! 1957: if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
! 1958: printf("ntfs_parserun: " \
! 1959: "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
! 1960: sz, len, *off);
! 1961: return (EINVAL);
! 1962: }
! 1963: for (i = 0; i < (sz & 0xF); i++)
! 1964: *cn += (u_int32_t) run[(*off)++] << (i << 3);
! 1965:
! 1966: return (0);
! 1967: }
! 1968: #endif
! 1969:
! 1970: /*
! 1971: * Process fixup routine on given buffer.
! 1972: */
! 1973: int
! 1974: ntfs_procfixups(
! 1975: struct ntfsmount * ntmp,
! 1976: u_int32_t magic,
! 1977: caddr_t buf,
! 1978: size_t len)
! 1979: {
! 1980: struct fixuphdr *fhp = (struct fixuphdr *) buf;
! 1981: int i;
! 1982: u_int16_t fixup;
! 1983: u_int16_t *fxp;
! 1984: u_int16_t *cfxp;
! 1985:
! 1986: if (fhp->fh_magic != magic) {
! 1987: printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
! 1988: fhp->fh_magic, magic);
! 1989: return (EINVAL);
! 1990: }
! 1991: if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
! 1992: printf("ntfs_procfixups: " \
! 1993: "bad fixups number: %d for %ld bytes block\n",
! 1994: fhp->fh_fnum, (long)len); /* XXX printf kludge */
! 1995: return (EINVAL);
! 1996: }
! 1997: if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
! 1998: printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
! 1999: return (EINVAL);
! 2000: }
! 2001: fxp = (u_int16_t *) (buf + fhp->fh_foff);
! 2002: cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
! 2003: fixup = *fxp++;
! 2004: for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
! 2005: if (*cfxp != fixup) {
! 2006: printf("ntfs_procfixups: fixup %d doesn't match\n", i);
! 2007: return (EINVAL);
! 2008: }
! 2009: *cfxp = *fxp;
! 2010: cfxp = (u_int16_t *)((caddr_t)cfxp + ntmp->ntm_bps);
! 2011: }
! 2012: return (0);
! 2013: }
! 2014:
! 2015: #if UNUSED_CODE
! 2016: int
! 2017: ntfs_runtocn(
! 2018: cn_t * cn,
! 2019: struct ntfsmount * ntmp,
! 2020: u_int8_t * run,
! 2021: u_long len,
! 2022: cn_t vcn)
! 2023: {
! 2024: cn_t ccn = 0;
! 2025: cn_t ccl = 0;
! 2026: u_long off = 0;
! 2027: int error = 0;
! 2028:
! 2029: #if NTFS_DEBUG
! 2030: int i;
! 2031: printf("ntfs_runtocn: run: %p, %ld bytes, vcn:%ld\n",
! 2032: run, len, (u_long) vcn);
! 2033: printf("ntfs_runtocn: run: ");
! 2034: for (i = 0; i < len; i++)
! 2035: printf("0x%02x ", run[i]);
! 2036: printf("\n");
! 2037: #endif
! 2038:
! 2039: if (NULL == run) {
! 2040: printf("ntfs_runtocn: run == NULL\n");
! 2041: return (EINVAL);
! 2042: }
! 2043: do {
! 2044: if (run[off] == 0) {
! 2045: printf("ntfs_runtocn: vcn too big\n");
! 2046: return (E2BIG);
! 2047: }
! 2048: vcn -= ccl;
! 2049: error = ntfs_parserun(&ccn, &ccl, run, len, &off);
! 2050: if (error) {
! 2051: printf("ntfs_runtocn: ntfs_parserun failed\n");
! 2052: return (error);
! 2053: }
! 2054: } while (ccl <= vcn);
! 2055: *cn = ccn + vcn;
! 2056: return (0);
! 2057: }
! 2058: #endif
! 2059:
! 2060: /*
! 2061: * this initializes toupper table & dependant variables to be ready for
! 2062: * later work
! 2063: */
! 2064: void
! 2065: ntfs_toupper_init()
! 2066: {
! 2067: ntfs_toupper_tab = (wchar *) NULL;
! 2068: lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0);
! 2069: ntfs_toupper_usecount = 0;
! 2070: }
! 2071:
! 2072: /*
! 2073: * if the ntfs_toupper_tab[] is filled already, just raise use count;
! 2074: * otherwise read the data from the filesystem we are currently mounting
! 2075: */
! 2076: int
! 2077: #ifndef __OpenBSD__
! 2078: ntfs_toupper_use(mp, ntmp)
! 2079: struct mount *mp;
! 2080: struct ntfsmount *ntmp;
! 2081: #else
! 2082: ntfs_toupper_use(mp, ntmp, p)
! 2083: struct mount *mp;
! 2084: struct ntfsmount *ntmp;
! 2085: struct proc *p;
! 2086: #endif
! 2087: {
! 2088: int error = 0;
! 2089: struct vnode *vp;
! 2090:
! 2091: /* get exclusive access */
! 2092: lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
! 2093:
! 2094: /* only read the translation data from a file if it hasn't been
! 2095: * read already */
! 2096: if (ntfs_toupper_tab)
! 2097: goto out;
! 2098:
! 2099: /*
! 2100: * Read in Unicode lowercase -> uppercase translation file.
! 2101: * XXX for now, just the first 256 entries are used anyway,
! 2102: * so don't bother reading more
! 2103: */
! 2104: MALLOC(ntfs_toupper_tab, wchar *, 256 * 256 * sizeof(wchar),
! 2105: M_NTFSRDATA, M_WAITOK);
! 2106:
! 2107: if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp)))
! 2108: goto out;
! 2109: error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
! 2110: 0, 256*256*sizeof(wchar), (char *) ntfs_toupper_tab,
! 2111: NULL);
! 2112: vput(vp);
! 2113:
! 2114: out:
! 2115: ntfs_toupper_usecount++;
! 2116: lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL);
! 2117: return (error);
! 2118: }
! 2119:
! 2120: /*
! 2121: * lower the use count and if it reaches zero, free the memory
! 2122: * tied by toupper table
! 2123: */
! 2124: void
! 2125: #ifndef __OpenBSD__
! 2126: ntfs_toupper_unuse()
! 2127: #else
! 2128: ntfs_toupper_unuse(p)
! 2129: struct proc *p;
! 2130: #endif
! 2131: {
! 2132: /* get exclusive access */
! 2133: lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
! 2134:
! 2135: ntfs_toupper_usecount--;
! 2136: if (ntfs_toupper_usecount == 0) {
! 2137: FREE(ntfs_toupper_tab, M_NTFSRDATA);
! 2138: ntfs_toupper_tab = NULL;
! 2139: }
! 2140: #ifdef DIAGNOSTIC
! 2141: else if (ntfs_toupper_usecount < 0) {
! 2142: panic("ntfs_toupper_unuse(): use count negative: %d",
! 2143: ntfs_toupper_usecount);
! 2144: }
! 2145: #endif
! 2146:
! 2147: /* release the lock */
! 2148: lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL);
! 2149: }
CVSweb