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

Cache object: b1d5ffbbdf46476c39f30c953066833b


[ 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.