The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/ntfs/ntfs_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: daa4e539ccda68b63e4bb76fb6f97a29


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.