LCOV - code coverage report
Current view: top level - ntfs - ntfs_subr.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 766 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13