ntfs_subr.c revision 120492
118334Speter/* $NetBSD: ntfs_subr.c,v 1.23 1999/10/31 19:45:26 jdolecek Exp $ */ 250397Sobrien 318334Speter/*- 418334Speter * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org) 518334Speter * All rights reserved. 618334Speter * 718334Speter * Redistribution and use in source and binary forms, with or without 818334Speter * modification, are permitted provided that the following conditions 918334Speter * are met: 1018334Speter * 1. Redistributions of source code must retain the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer. 1218334Speter * 2. Redistributions in binary form must reproduce the above copyright 1318334Speter * notice, this list of conditions and the following disclaimer in the 1418334Speter * documentation and/or other materials provided with the distribution. 1518334Speter * 1618334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1718334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1818334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1918334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2018334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2118334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2218334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2318334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2418334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2518334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2618334Speter * SUCH DAMAGE. 2718334Speter * 2818334Speter * $FreeBSD: head/sys/fs/ntfs/ntfs_subr.c 120492 2003-09-26 20:26:25Z fjoe $ 2918334Speter */ 3018334Speter 3118334Speter#include <sys/param.h> 3250397Sobrien#include <sys/types.h> 3318334Speter#include <sys/systm.h> 3418334Speter#include <sys/namei.h> 3518334Speter#include <sys/kernel.h> 3618334Speter#include <sys/vnode.h> 3750397Sobrien#include <sys/mount.h> 3850397Sobrien#include <sys/bio.h> 3950397Sobrien#include <sys/buf.h> 4018334Speter#include <sys/file.h> 4118334Speter#include <sys/malloc.h> 4218334Speter#include <sys/lock.h> 4318334Speter#include <sys/iconv.h> 4418334Speter 4550397Sobrien/* #define NTFS_DEBUG 1 */ 4618334Speter#include <fs/ntfs/ntfs.h> 4718334Speter#include <fs/ntfs/ntfsmount.h> 4818334Speter#include <fs/ntfs/ntfs_inode.h> 4918334Speter#include <fs/ntfs/ntfs_vfsops.h> 5018334Speter#include <fs/ntfs/ntfs_subr.h> 5118334Speter#include <fs/ntfs/ntfs_compr.h> 5218334Speter#include <fs/ntfs/ntfs_ihash.h> 5318334Speter 5418334SpeterMALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information"); 5518334SpeterMALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data"); 5618334SpeterMALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage"); 5718334SpeterMALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary"); 5818334Speter 5918334Speterstatic int ntfs_ntlookupattr(struct ntfsmount *, const char *, int, int *, char **); 6018334Speterstatic int ntfs_findvattr(struct ntfsmount *, struct ntnode *, struct ntvattr **, struct ntvattr **, u_int32_t, const char *, size_t, cn_t); 6118334Speterstatic int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t); 6218334Speterstatic int ntfs_uastrcmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t); 6318334Speter 6418334Speter/* table for mapping Unicode chars into uppercase; it's filled upon first 6518334Speter * ntfs mount, freed upon last ntfs umount */ 6618334Speterstatic wchar *ntfs_toupper_tab; 6718334Speter#define NTFS_TOUPPER(ch) (ntfs_toupper_tab[(ch)]) 6818334Speterstatic struct lock ntfs_toupper_lock; 6918334Speterstatic signed int ntfs_toupper_usecount; 7018334Speter 7118334Speterstruct iconv_functions *ntfs_iconv = NULL; 7218334Speter 7318334Speter/* support macro for ntfs_ntvattrget() */ 7450397Sobrien#define NTFS_AALPCMP(aalp,type,name,namelen) ( \ 7550397Sobrien (aalp->al_type == type) && (aalp->al_namelen == namelen) && \ 7618334Speter !NTFS_UASTRCMP(aalp->al_name,aalp->al_namelen,name,namelen) ) 7718334Speter 7818334Speter/* 7918334Speter * 8018334Speter */ 8118334Speterint 8218334Speterntfs_ntvattrrele(vap) 8318334Speter struct ntvattr * vap; 8418334Speter{ 8518334Speter dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n", 8618334Speter vap->va_ip->i_number, vap->va_type)); 8718334Speter 8818334Speter ntfs_ntrele(vap->va_ip); 8918334Speter 9018334Speter return (0); 9118334Speter} 9218334Speter 9318334Speter/* 9418334Speter * find the attribute in the ntnode 9518334Speter */ 9618334Speterstatic int 9718334Speterntfs_findvattr(ntmp, ip, lvapp, vapp, type, name, namelen, vcn) 9818334Speter struct ntfsmount *ntmp; 9918334Speter struct ntnode *ip; 10018334Speter struct ntvattr **lvapp, **vapp; 10118334Speter u_int32_t type; 10218334Speter const char *name; 10318334Speter size_t namelen; 10418334Speter cn_t vcn; 10518334Speter{ 10618334Speter int error; 10718334Speter struct ntvattr *vap; 10818334Speter 10918334Speter if((ip->i_flag & IN_LOADED) == 0) { 11018334Speter dprintf(("ntfs_findvattr: node not loaded, ino: %d\n", 11118334Speter ip->i_number)); 11218334Speter error = ntfs_loadntnode(ntmp,ip); 11318334Speter if (error) { 11418334Speter printf("ntfs_findvattr: FAILED TO LOAD INO: %d\n", 11518334Speter ip->i_number); 11618334Speter return (error); 11718334Speter } 11818334Speter } 11918334Speter 12018334Speter *lvapp = NULL; 12118334Speter *vapp = NULL; 12218334Speter LIST_FOREACH(vap, &ip->i_valist, va_list) { 12318334Speter ddprintf(("ntfs_findvattr: type: 0x%x, vcn: %d - %d\n", \ 12418334Speter vap->va_type, (u_int32_t) vap->va_vcnstart, \ 12518334Speter (u_int32_t) vap->va_vcnend)); 12618334Speter if ((vap->va_type == type) && 12718334Speter (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) && 12818334Speter (vap->va_namelen == namelen) && 12918334Speter (strncmp(name, vap->va_name, namelen) == 0)) { 13018334Speter *vapp = vap; 13118334Speter ntfs_ntref(vap->va_ip); 13218334Speter return (0); 13318334Speter } 13418334Speter if (vap->va_type == NTFS_A_ATTRLIST) 13518334Speter *lvapp = vap; 13618334Speter } 13718334Speter 13818334Speter return (-1); 13918334Speter} 14018334Speter 14118334Speter/* 14218334Speter * Search attribute specifed in ntnode (load ntnode if nessecary). 14318334Speter * If not found but ATTR_A_ATTRLIST present, read it in and search throught. 14418334Speter * VOP_VGET node needed, and lookup througth it's ntnode (load if nessesary). 14518334Speter * 14618334Speter * ntnode should be locked 14718334Speter */ 14818334Speterint 14918334Speterntfs_ntvattrget( 15018334Speter struct ntfsmount * ntmp, 15118334Speter struct ntnode * ip, 15218334Speter u_int32_t type, 15318334Speter const char *name, 15418334Speter cn_t vcn, 15518334Speter struct ntvattr ** vapp) 15618334Speter{ 15718334Speter struct ntvattr *lvap = NULL; 15818334Speter struct attr_attrlist *aalp; 15918334Speter struct attr_attrlist *nextaalp; 16018334Speter struct vnode *newvp; 16118334Speter struct ntnode *newip; 16218334Speter caddr_t alpool; 16318334Speter size_t namelen, len; 16418334Speter int error; 16518334Speter 16618334Speter *vapp = NULL; 16718334Speter 16818334Speter if (name) { 16918334Speter dprintf(("ntfs_ntvattrget: " \ 17018334Speter "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 17118334Speter ip->i_number, type, name, (u_int32_t) vcn)); 17218334Speter namelen = strlen(name); 17318334Speter } else { 17418334Speter dprintf(("ntfs_ntvattrget: " \ 17518334Speter "ino: %d, type: 0x%x, vcn: %d\n", \ 17618334Speter ip->i_number, type, (u_int32_t) vcn)); 17718334Speter name = ""; 17818334Speter namelen = 0; 17918334Speter } 18018334Speter 18118334Speter error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn); 18218334Speter if (error >= 0) 18318334Speter return (error); 18418334Speter 18518334Speter if (!lvap) { 18618334Speter dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \ 18718334Speter "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 18818334Speter ip->i_number, type, name, (u_int32_t) vcn)); 18918334Speter return (ENOENT); 19018334Speter } 19118334Speter /* Scan $ATTRIBUTE_LIST for requested attribute */ 19218334Speter len = lvap->va_datalen; 19318334Speter MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK); 19418334Speter error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len, 19518334Speter NULL); 19618334Speter if (error) 19750397Sobrien goto out; 19850397Sobrien 19918334Speter aalp = (struct attr_attrlist *) alpool; 20018334Speter nextaalp = NULL; 20118334Speter 20218334Speter for(; len > 0; aalp = nextaalp) { 20318334Speter dprintf(("ntfs_ntvattrget: " \ 20418334Speter "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \ 20518334Speter aalp->al_inumber, aalp->al_type, \ 20618334Speter (u_int32_t) aalp->al_vcnstart)); 20718334Speter 20818334Speter if (len > aalp->reclen) { 20918334Speter nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *); 21018334Speter } else { 21118334Speter nextaalp = NULL; 21218334Speter } 21318334Speter len -= aalp->reclen; 21418334Speter 21518334Speter if (!NTFS_AALPCMP(aalp, type, name, namelen) || 21618334Speter (nextaalp && (nextaalp->al_vcnstart <= vcn) && 21718334Speter NTFS_AALPCMP(nextaalp, type, name, namelen))) 21818334Speter continue; 21918334Speter 22018334Speter dprintf(("ntfs_ntvattrget: attribute in ino: %d\n", 22118334Speter aalp->al_inumber)); 22218334Speter 22318334Speter /* this is not a main record, so we can't use just plain 22418334Speter vget() */ 22518334Speter error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber, 22618334Speter NTFS_A_DATA, NULL, LK_EXCLUSIVE, 22718334Speter VG_EXT, curthread, &newvp); 22818334Speter if (error) { 22918334Speter printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n", 23018334Speter aalp->al_inumber); 23118334Speter goto out; 23218334Speter } 23318334Speter newip = VTONT(newvp); 23418334Speter /* XXX have to lock ntnode */ 23518334Speter error = ntfs_findvattr(ntmp, newip, &lvap, vapp, 23618334Speter type, name, namelen, vcn); 23718334Speter vput(newvp); 23818334Speter if (error == 0) 23918334Speter goto out; 24018334Speter printf("ntfs_ntvattrget: ATTRLIST ERROR.\n"); 24118334Speter break; 24218334Speter } 24318334Speter error = ENOENT; 24418334Speter 24518334Speter dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \ 24618334Speter "ino: %d, type: 0x%x, name: %.*s, vcn: %d\n", \ 24718334Speter ip->i_number, type, (int) namelen, name, (u_int32_t) vcn)); 24818334Speterout: 24918334Speter FREE(alpool, M_TEMP); 25018334Speter return (error); 25118334Speter} 25218334Speter 25318334Speter/* 25418334Speter * Read ntnode from disk, make ntvattr list. 25518334Speter * 25618334Speter * ntnode should be locked 25718334Speter */ 25818334Speterint 25918334Speterntfs_loadntnode( 26018334Speter struct ntfsmount * ntmp, 26118334Speter struct ntnode * ip) 26218334Speter{ 26318334Speter struct filerec *mfrp; 26418334Speter daddr_t bn; 26518334Speter int error,off; 26650397Sobrien struct attr *ap; 26750397Sobrien struct ntvattr *nvap; 26850397Sobrien 26950397Sobrien dprintf(("ntfs_loadntnode: loading ino: %d\n",ip->i_number)); 27050397Sobrien 27150397Sobrien MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec), 27218334Speter M_TEMP, M_WAITOK); 27318334Speter 27418334Speter if (ip->i_number < NTFS_SYSNODESNUM) { 27518334Speter struct buf *bp; 27618334Speter 27718334Speter dprintf(("ntfs_loadntnode: read system node\n")); 27818334Speter 27918334Speter bn = ntfs_cntobn(ntmp->ntm_mftcn) + 28018334Speter ntmp->ntm_bpmftrec * ip->i_number; 28118334Speter 28218334Speter error = bread(ntmp->ntm_devvp, 28318334Speter bn, ntfs_bntob(ntmp->ntm_bpmftrec), 28418334Speter NOCRED, &bp); 28518334Speter if (error) { 28618334Speter printf("ntfs_loadntnode: BREAD FAILED\n"); 28718334Speter brelse(bp); 28818334Speter goto out; 28918334Speter } 29018334Speter memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec)); 29118334Speter bqrelse(bp); 29218334Speter } else { 29318334Speter struct vnode *vp; 29418334Speter 29518334Speter vp = ntmp->ntm_sysvn[NTFS_MFTINO]; 29618334Speter error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 29718334Speter ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec), 29818334Speter ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL); 29918334Speter if (error) { 30018334Speter printf("ntfs_loadntnode: ntfs_readattr failed\n"); 30118334Speter goto out; 30218334Speter } 30318334Speter } 30418334Speter 30518334Speter /* Check if magic and fixups are correct */ 30618334Speter error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp, 30718334Speter ntfs_bntob(ntmp->ntm_bpmftrec)); 30818334Speter if (error) { 30918334Speter printf("ntfs_loadntnode: BAD MFT RECORD %d\n", 31018334Speter (u_int32_t) ip->i_number); 31118334Speter goto out; 31218334Speter } 31318334Speter 31418334Speter dprintf(("ntfs_loadntnode: load attrs for ino: %d\n",ip->i_number)); 31518334Speter off = mfrp->fr_attroff; 31618334Speter ap = (struct attr *) ((caddr_t)mfrp + off); 31718334Speter 31818334Speter LIST_INIT(&ip->i_valist); 31918334Speter 32018334Speter while (ap->a_hdr.a_type != -1) { 32118334Speter error = ntfs_attrtontvattr(ntmp, &nvap, ap); 32218334Speter if (error) 32318334Speter break; 32418334Speter nvap->va_ip = ip; 32518334Speter 32618334Speter LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list); 32718334Speter 32818334Speter off += ap->a_hdr.reclen; 32918334Speter ap = (struct attr *) ((caddr_t)mfrp + off); 33018334Speter } 33118334Speter if (error) { 33218334Speter printf("ntfs_loadntnode: failed to load attr ino: %d\n", 33318334Speter ip->i_number); 33418334Speter goto out; 33518334Speter } 33618334Speter 33718334Speter ip->i_mainrec = mfrp->fr_mainrec; 33818334Speter ip->i_nlink = mfrp->fr_nlink; 33918334Speter ip->i_frflag = mfrp->fr_flags; 34018334Speter 34118334Speter ip->i_flag |= IN_LOADED; 34218334Speter 34318334Speterout: 34418334Speter FREE(mfrp, M_TEMP); 34518334Speter return (error); 34618334Speter} 34718334Speter 34818334Speter/* 34918334Speter * Routine locks ntnode and increase usecount, just opposite of 35018334Speter * ntfs_ntput(). 35118334Speter */ 35218334Speterint 35318334Speterntfs_ntget(ip) 35418334Speter struct ntnode *ip; 35518334Speter{ 35618334Speter dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n", 35718334Speter ip->i_number, ip, ip->i_usecount)); 35818334Speter 35918334Speter mtx_lock(&ip->i_interlock); 36018334Speter ip->i_usecount++; 36118334Speter lockmgr(&ip->i_lock, LK_EXCLUSIVE | LK_INTERLOCK, &ip->i_interlock, 36218334Speter NULL); 36318334Speter 36418334Speter return 0; 36518334Speter} 36618334Speter 36718334Speter/* 36818334Speter * Routine search ntnode in hash, if found: lock, inc usecount and return. 36918334Speter * If not in hash allocate structure for ntnode, prefill it, lock, 37018334Speter * inc count and return. 37118334Speter * 37218334Speter * ntnode returned locked 37318334Speter */ 37418334Speterint 37518334Speterntfs_ntlookup( 37618334Speter struct ntfsmount * ntmp, 37718334Speter ino_t ino, 37818334Speter struct ntnode ** ipp) 37918334Speter{ 38018334Speter struct ntnode *ip; 38118334Speter 38218334Speter dprintf(("ntfs_ntlookup: looking for ntnode %d\n", ino)); 38318334Speter 38418334Speter do { 38518334Speter if ((ip = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) { 38618334Speter ntfs_ntget(ip); 38718334Speter dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n", 38818334Speter ino, ip, ip->i_usecount)); 38918334Speter *ipp = ip; 39018334Speter return (0); 39118334Speter } 39218334Speter } while (lockmgr(&ntfs_hashlock, LK_EXCLUSIVE | LK_SLEEPFAIL, NULL, 39318334Speter NULL)); 39418334Speter 39518334Speter MALLOC(ip, struct ntnode *, sizeof(struct ntnode), M_NTFSNTNODE, 39618334Speter M_WAITOK | M_ZERO); 39718334Speter ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip)); 39818334Speter 39918334Speter /* Generic initialization */ 40018334Speter ip->i_devvp = ntmp->ntm_devvp; 40118334Speter ip->i_dev = ntmp->ntm_dev; 40218334Speter ip->i_number = ino; 40318334Speter ip->i_mp = ntmp; 40418334Speter 40518334Speter LIST_INIT(&ip->i_fnlist); 40650397Sobrien VREF(ip->i_devvp); 40718334Speter 40818334Speter /* init lock and lock the newborn ntnode */ 40918334Speter lockinit(&ip->i_lock, PINOD, "ntnode", 0, LK_EXCLUSIVE); 41018334Speter mtx_init(&ip->i_interlock, "ntnode interlock", NULL, MTX_DEF); 41118334Speter ntfs_ntget(ip); 41218334Speter 41318334Speter ntfs_nthashins(ip); 41418334Speter 41518334Speter lockmgr(&ntfs_hashlock, LK_RELEASE, NULL, NULL); 41618334Speter 41718334Speter *ipp = ip; 41818334Speter 41918334Speter dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n", 42018334Speter ino, ip, ip->i_usecount)); 42118334Speter 42218334Speter return (0); 42318334Speter} 42418334Speter 42518334Speter/* 42618334Speter * Decrement usecount of ntnode and unlock it, if usecount reach zero, 42718334Speter * deallocate ntnode. 42818334Speter * 42950397Sobrien * ntnode should be locked on entry, and unlocked on return. 43050397Sobrien */ 43118334Spetervoid 43218334Speterntfs_ntput(ip) 43318334Speter struct ntnode *ip; 43418334Speter{ 43518334Speter struct ntvattr *vap; 43618334Speter 43718334Speter dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n", 43818334Speter ip->i_number, ip, ip->i_usecount)); 43918334Speter 44018334Speter mtx_lock(&ip->i_interlock); 44118334Speter ip->i_usecount--; 44218334Speter 44318334Speter#ifdef DIAGNOSTIC 44418334Speter if (ip->i_usecount < 0) { 44518334Speter panic("ntfs_ntput: ino: %d usecount: %d \n", 44618334Speter ip->i_number,ip->i_usecount); 44718334Speter } 44818334Speter#endif 44918334Speter 45018334Speter if (ip->i_usecount > 0) { 45118334Speter lockmgr(&ip->i_lock, LK_RELEASE|LK_INTERLOCK, &ip->i_interlock, 45218334Speter NULL); 45318334Speter return; 45418334Speter } 45518334Speter 45618334Speter dprintf(("ntfs_ntput: deallocating ntnode: %d\n", ip->i_number)); 45750397Sobrien 45818334Speter if (LIST_FIRST(&ip->i_fnlist)) 45918334Speter panic("ntfs_ntput: ntnode has fnodes\n"); 46018334Speter 46118334Speter ntfs_nthashrem(ip); 46218334Speter 46318334Speter while ((vap = LIST_FIRST(&ip->i_valist)) != NULL) { 46418334Speter LIST_REMOVE(vap,va_list); 46518334Speter ntfs_freentvattr(vap); 46618334Speter } 46718334Speter mtx_unlock(&ip->i_interlock); 46818334Speter mtx_destroy(&ip->i_interlock); 46918334Speter lockdestroy(&ip->i_lock); 47018334Speter vrele(ip->i_devvp); 47118334Speter FREE(ip, M_NTFSNTNODE); 47218334Speter} 47318334Speter 47418334Speter/* 47518334Speter * increment usecount of ntnode 47618334Speter */ 47718334Spetervoid 47818334Speterntfs_ntref(ip) 47918334Speter struct ntnode *ip; 48018334Speter{ 48118334Speter mtx_lock(&ip->i_interlock); 48218334Speter ip->i_usecount++; 48318334Speter mtx_unlock(&ip->i_interlock); 48418334Speter 48518334Speter dprintf(("ntfs_ntref: ino %d, usecount: %d\n", 48618334Speter ip->i_number, ip->i_usecount)); 48718334Speter 48818334Speter} 48918334Speter 49018334Speter/* 49118334Speter * Decrement usecount of ntnode. 49218334Speter */ 49318334Spetervoid 49418334Speterntfs_ntrele(ip) 49518334Speter struct ntnode *ip; 49618334Speter{ 49718334Speter dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n", 49818334Speter ip->i_number, ip, ip->i_usecount)); 49918334Speter 50018334Speter mtx_lock(&ip->i_interlock); 50118334Speter ip->i_usecount--; 50218334Speter 50318334Speter if (ip->i_usecount < 0) 50418334Speter panic("ntfs_ntrele: ino: %d usecount: %d \n", 50518334Speter ip->i_number,ip->i_usecount); 50618334Speter mtx_unlock(&ip->i_interlock); 50718334Speter} 50818334Speter 50918334Speter/* 51018334Speter * Deallocate all memory allocated for ntvattr 51118334Speter */ 51218334Spetervoid 51318334Speterntfs_freentvattr(vap) 51418334Speter struct ntvattr * vap; 51518334Speter{ 51618334Speter if (vap->va_flag & NTFS_AF_INRUN) { 51718334Speter if (vap->va_vruncn) 51818334Speter FREE(vap->va_vruncn, M_NTFSRUN); 51950397Sobrien if (vap->va_vruncl) 52050397Sobrien FREE(vap->va_vruncl, M_NTFSRUN); 52150397Sobrien } else { 52218334Speter if (vap->va_datap) 52318334Speter FREE(vap->va_datap, M_NTFSRDATA); 52418334Speter } 52518334Speter FREE(vap, M_NTFSNTVATTR); 52618334Speter} 52718334Speter 52818334Speter/* 52918334Speter * Convert disk image of attribute into ntvattr structure, 53018334Speter * runs are expanded also. 53118334Speter */ 53218334Speterint 53318334Speterntfs_attrtontvattr( 53418334Speter struct ntfsmount * ntmp, 53518334Speter struct ntvattr ** rvapp, 53650397Sobrien struct attr * rap) 53718334Speter{ 53818334Speter int error, i; 53918334Speter struct ntvattr *vap; 54018334Speter 54118334Speter error = 0; 54218334Speter *rvapp = NULL; 54318334Speter 54418334Speter MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr), 54518334Speter M_NTFSNTVATTR, M_WAITOK | M_ZERO); 54618334Speter vap->va_ip = NULL; 54718334Speter vap->va_flag = rap->a_hdr.a_flag; 54818334Speter vap->va_type = rap->a_hdr.a_type; 54918334Speter vap->va_compression = rap->a_hdr.a_compression; 55018334Speter vap->va_index = rap->a_hdr.a_index; 55118334Speter 55218334Speter ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index)); 55318334Speter 55418334Speter vap->va_namelen = rap->a_hdr.a_namelen; 55518334Speter if (rap->a_hdr.a_namelen) { 55618334Speter wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff); 55718334Speter ddprintf((", name:[")); 55818334Speter for (i = 0; i < vap->va_namelen; i++) { 55918334Speter vap->va_name[i] = unp[i]; 56018334Speter ddprintf(("%c", vap->va_name[i])); 56118334Speter } 56218334Speter ddprintf(("]")); 56318334Speter } 56418334Speter if (vap->va_flag & NTFS_AF_INRUN) { 56518334Speter ddprintf((", nonres.")); 56618334Speter vap->va_datalen = rap->a_nr.a_datalen; 56718334Speter vap->va_allocated = rap->a_nr.a_allocated; 56818334Speter vap->va_vcnstart = rap->a_nr.a_vcnstart; 56918334Speter vap->va_vcnend = rap->a_nr.a_vcnend; 57018334Speter vap->va_compressalg = rap->a_nr.a_compressalg; 57118334Speter error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl), 57218334Speter &(vap->va_vruncnt), 57318334Speter (caddr_t) rap + rap->a_nr.a_dataoff); 57418334Speter } else { 57518334Speter vap->va_compressalg = 0; 57618334Speter ddprintf((", res.")); 57718334Speter vap->va_datalen = rap->a_r.a_datalen; 57818334Speter vap->va_allocated = rap->a_r.a_datalen; 57918334Speter vap->va_vcnstart = 0; 58018334Speter vap->va_vcnend = ntfs_btocn(vap->va_allocated); 58118334Speter MALLOC(vap->va_datap, caddr_t, vap->va_datalen, 58218334Speter M_NTFSRDATA, M_WAITOK); 58318334Speter memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff, 58418334Speter rap->a_r.a_datalen); 58518334Speter } 58618334Speter ddprintf((", len: %d", vap->va_datalen)); 58718334Speter 58818334Speter if (error) 58918334Speter FREE(vap, M_NTFSNTVATTR); 59018334Speter else 59118334Speter *rvapp = vap; 59218334Speter 59318334Speter ddprintf(("\n")); 59418334Speter 59518334Speter return (error); 59618334Speter} 59718334Speter 59818334Speter/* 59918334Speter * Expand run into more utilizable and more memory eating format. 60018334Speter */ 60118334Speterint 60218334Speterntfs_runtovrun( 60318334Speter cn_t ** rcnp, 60418334Speter cn_t ** rclp, 60518334Speter u_long * rcntp, 60618334Speter u_int8_t * run) 60718334Speter{ 60818334Speter u_int32_t off; 60918334Speter u_int32_t sz, i; 61018334Speter cn_t *cn; 61118334Speter cn_t *cl; 61218334Speter u_long cnt; 61318334Speter cn_t prev; 61418334Speter cn_t tmp; 61518334Speter 61618334Speter off = 0; 61718334Speter cnt = 0; 61818334Speter i = 0; 61918334Speter while (run[off]) { 62018334Speter off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1; 62118334Speter cnt++; 62218334Speter } 62318334Speter MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK); 62418334Speter MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK); 62518334Speter 62618334Speter off = 0; 62718334Speter cnt = 0; 62818334Speter prev = 0; 62918334Speter while (run[off]) { 63018334Speter 63118334Speter sz = run[off++]; 63218334Speter cl[cnt] = 0; 63318334Speter 63418334Speter for (i = 0; i < (sz & 0xF); i++) 63518334Speter cl[cnt] += (u_int32_t) run[off++] << (i << 3); 63618334Speter 63718334Speter sz >>= 4; 63818334Speter if (run[off + sz - 1] & 0x80) { 63918334Speter tmp = ((u_int64_t) - 1) << (sz << 3); 64018334Speter for (i = 0; i < sz; i++) 64118334Speter tmp |= (u_int64_t) run[off++] << (i << 3); 64218334Speter } else { 64318334Speter tmp = 0; 64418334Speter for (i = 0; i < sz; i++) 64518334Speter tmp |= (u_int64_t) run[off++] << (i << 3); 64618334Speter } 64718334Speter if (tmp) 64818334Speter prev = cn[cnt] = prev + tmp; 64918334Speter else 65018334Speter cn[cnt] = tmp; 65118334Speter 65218334Speter cnt++; 65318334Speter } 65418334Speter *rcnp = cn; 65518334Speter *rclp = cl; 65618334Speter *rcntp = cnt; 65718334Speter return (0); 65818334Speter} 65918334Speter 66018334Speter/* 66118334Speter * Compare unicode and ascii string case insens. 66218334Speter */ 66318334Speterstatic int 66418334Speterntfs_uastricmp(ntmp, ustr, ustrlen, astr, astrlen) 66518334Speter struct ntfsmount *ntmp; 66618334Speter const wchar *ustr; 66718334Speter size_t ustrlen; 66818334Speter const char *astr; 66918334Speter size_t astrlen; 67018334Speter{ 67118334Speter int len; 67218334Speter size_t i, j, mbstrlen = astrlen; 67318334Speter int res; 67418334Speter wchar wc; 67518334Speter 67618334Speter if (ntmp->ntm_ic_l2u) { 67718334Speter for (i = 0, j = 0; i < ustrlen && j < astrlen; i++, j++) { 67818334Speter if (j < astrlen -1) { 67918334Speter wc = (wchar)astr[j]<<8 | (astr[j+1]&0xFF); 68018334Speter len = 2; 68118334Speter } else { 68218334Speter wc = (wchar)astr[j]<<8 & 0xFF00; 68318334Speter len = 1; 68418334Speter } 68518334Speter res = ((int) NTFS_TOUPPER(ustr[i])) - 68618334Speter ((int)NTFS_TOUPPER(NTFS_82U(wc, &len))); 68718334Speter j += len - 1; 68818334Speter mbstrlen -= len - 1; 68918334Speter 69018334Speter if (res) 69118334Speter return res; 69218334Speter } 69318334Speter } else { 69418334Speter /* 69518334Speter * We use NTFS_82U(NTFS_U28(c)) to get rid of unicode 69618334Speter * symbols not covered by translation table 69718334Speter */ 69818334Speter for (i = 0; i < ustrlen && i < astrlen; i++) { 69918334Speter res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i]), &len))) - 70018334Speter ((int)NTFS_TOUPPER(NTFS_82U((wchar)astr[i], &len))); 70118334Speter if (res) 70218334Speter return res; 70318334Speter } 70418334Speter } 70518334Speter return (ustrlen - mbstrlen); 70618334Speter} 70718334Speter 70818334Speter/* 70918334Speter * Compare unicode and ascii string case sens. 71018334Speter */ 71118334Speterstatic int 71218334Speterntfs_uastrcmp(ntmp, ustr, ustrlen, astr, astrlen) 71318334Speter struct ntfsmount *ntmp; 71418334Speter const wchar *ustr; 71518334Speter size_t ustrlen; 71618334Speter const char *astr; 71718334Speter size_t astrlen; 71818334Speter{ 71918334Speter char u, l; 72018334Speter size_t i, j, mbstrlen = astrlen; 72118334Speter int res; 72218334Speter wchar wc; 72318334Speter 72418334Speter for (i = 0, j = 0; (i < ustrlen) && (j < astrlen); i++, j++) { 72518334Speter res = 0; 72618334Speter wc = NTFS_U28(ustr[i]); 72718334Speter u = (char)(wc>>8); 72818334Speter l = (char)wc; 72918334Speter if (u != '\0' && j < astrlen -1) { 73018334Speter res = (int) (u - astr[j++]); 73118334Speter mbstrlen--; 73218334Speter } 73318334Speter res = (res<<8) + (int) (l - astr[j]); 73418334Speter if (res) 73518334Speter return res; 73618334Speter } 73718334Speter return (ustrlen - mbstrlen); 73818334Speter} 73918334Speter 74018334Speter/* 74118334Speter * Search fnode in ntnode, if not found allocate and preinitialize. 74218334Speter * 74318334Speter * ntnode should be locked on entry. 74418334Speter */ 74518334Speterint 74618334Speterntfs_fget( 74718334Speter struct ntfsmount *ntmp, 74818334Speter struct ntnode *ip, 74918334Speter int attrtype, 75050397Sobrien char *attrname, 75150397Sobrien struct fnode **fpp) 75218334Speter{ 75318334Speter struct fnode *fp; 75418334Speter 75518334Speter dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n", 75618334Speter ip->i_number,attrtype, attrname?attrname:"")); 75718334Speter *fpp = NULL; 75818334Speter LIST_FOREACH(fp, &ip->i_fnlist, f_fnlist){ 75918334Speter dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n", 76018334Speter fp->f_attrtype, fp->f_attrname?fp->f_attrname:"")); 76118334Speter 76218334Speter if ((attrtype == fp->f_attrtype) && 76318334Speter ((!attrname && !fp->f_attrname) || 76418334Speter (attrname && fp->f_attrname && 76518334Speter !strcmp(attrname,fp->f_attrname)))){ 76618334Speter dprintf(("ntfs_fget: found existed: %p\n",fp)); 76718334Speter *fpp = fp; 76818334Speter } 76918334Speter } 77018334Speter 77118334Speter if (*fpp) 77218334Speter return (0); 77318334Speter 77418334Speter MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, 77518334Speter M_WAITOK | M_ZERO); 77618334Speter dprintf(("ntfs_fget: allocating fnode: %p\n",fp)); 77718334Speter 77818334Speter fp->f_ip = ip; 77950397Sobrien if (attrname) { 78050397Sobrien fp->f_flag |= FN_AATTRNAME; 78118334Speter MALLOC(fp->f_attrname, char *, strlen(attrname)+1, M_TEMP, M_WAITOK); 78218334Speter strcpy(fp->f_attrname, attrname); 78318334Speter } else 78418334Speter fp->f_attrname = NULL; 78518334Speter fp->f_attrtype = attrtype; 78618334Speter 78718334Speter ntfs_ntref(ip); 78818334Speter 78918334Speter LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist); 79018334Speter 79150397Sobrien *fpp = fp; 79250397Sobrien 79318334Speter return (0); 79418334Speter} 79518334Speter 79618334Speter/* 79718334Speter * Deallocate fnode, remove it from ntnode's fnode list. 79818334Speter * 79918334Speter * ntnode should be locked. 80018334Speter */ 80118334Spetervoid 80218334Speterntfs_frele( 80318334Speter struct fnode *fp) 80418334Speter{ 80518334Speter struct ntnode *ip = FTONT(fp); 80618334Speter 80718334Speter dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip)); 80818334Speter 80918334Speter dprintf(("ntfs_frele: deallocating fnode\n")); 81018334Speter LIST_REMOVE(fp,f_fnlist); 81118334Speter if (fp->f_flag & FN_AATTRNAME) 81218334Speter FREE(fp->f_attrname, M_TEMP); 81318334Speter if (fp->f_dirblbuf) 81418334Speter FREE(fp->f_dirblbuf, M_NTFSDIR); 81518334Speter FREE(fp, M_NTFSFNODE); 81618334Speter ntfs_ntrele(ip); 81718334Speter} 81818334Speter 81918334Speter/* 82018334Speter * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME], 82118334Speter * $ATTR_TYPE is searched in attrdefs read from $AttrDefs. 82218334Speter * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed. 82318334Speter */ 82418334Speterstatic int 82518334Speterntfs_ntlookupattr( 82618334Speter struct ntfsmount * ntmp, 82718334Speter const char * name, 82818334Speter int namelen, 82918334Speter int *attrtype, 83018334Speter char **attrname) 83118334Speter{ 83218334Speter const char *sys; 83318334Speter size_t syslen, i; 83418334Speter struct ntvattrdef *adp; 83518334Speter 83618334Speter if (namelen == 0) 83718334Speter return (0); 83818334Speter 83918334Speter if (name[0] == '$') { 84050397Sobrien sys = name; 84118334Speter for (syslen = 0; syslen < namelen; syslen++) { 84218334Speter if(sys[syslen] == ':') { 84318334Speter name++; 84418334Speter namelen--; 84518334Speter break; 84618334Speter } 84718334Speter } 84818334Speter name += syslen; 84918334Speter namelen -= syslen; 85018334Speter 85118334Speter adp = ntmp->ntm_ad; 85218334Speter for (i = 0; i < ntmp->ntm_adnum; i++, adp++){ 85318334Speter if (syslen != adp->ad_namelen || 85418334Speter strncmp(sys, adp->ad_name, syslen) != 0) 85518334Speter continue; 85618334Speter 85718334Speter *attrtype = adp->ad_type; 85818334Speter goto out; 85918334Speter } 86018334Speter return (ENOENT); 86118334Speter } else 86218334Speter *attrtype = NTFS_A_DATA; 86318334Speter 86450397Sobrien out: 86518334Speter if (namelen) { 86618334Speter MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK); 86718334Speter memcpy((*attrname), name, namelen); 86818334Speter (*attrname)[namelen] = '\0'; 86918334Speter } 87018334Speter 87118334Speter return (0); 87218334Speter} 87318334Speter 87418334Speter/* 87518334Speter * Lookup specifed node for filename, matching cnp, 87618334Speter * return fnode filled. 87718334Speter */ 87818334Speterint 87918334Speterntfs_ntlookupfile( 88018334Speter struct ntfsmount * ntmp, 88118334Speter struct vnode * vp, 88218334Speter struct componentname * cnp, 88318334Speter struct vnode ** vpp) 88418334Speter{ 88518334Speter struct fnode *fp = VTOF(vp); 88618334Speter struct ntnode *ip = FTONT(fp); 88718334Speter struct ntvattr *vap; /* Root attribute */ 88818334Speter cn_t cn; /* VCN in current attribute */ 88918334Speter caddr_t rdbuf; /* Buffer to read directory's blocks */ 89018334Speter u_int32_t blsize; 89118334Speter u_int32_t rdsize; /* Length of data to read from current block */ 89218334Speter struct attr_indexentry *iep; 89350397Sobrien int error, res, anamelen, fnamelen; 89418334Speter const char *fname,*aname; 89518334Speter u_int32_t aoff; 89618334Speter int attrtype = NTFS_A_DATA; 89718334Speter char *attrname = NULL; 89818334Speter struct fnode *nfp; 89918334Speter struct vnode *nvp; 90018334Speter enum vtype f_type; 90118334Speter 90218334Speter error = ntfs_ntget(ip); 90318334Speter if (error) 90418334Speter return (error); 90518334Speter 90618334Speter error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 90718334Speter if (error || (vap->va_flag & NTFS_AF_INRUN)) 90818334Speter return (ENOTDIR); 90918334Speter 91018334Speter blsize = vap->va_a_iroot->ir_size; 91118334Speter rdsize = vap->va_datalen; 91218334Speter 91318334Speter /* 91418334Speter * Divide file name into: foofilefoofilefoofile[:attrspec] 91518334Speter * Store like this: fname:fnamelen [aname:anamelen] 91618334Speter */ 91718334Speter fname = cnp->cn_nameptr; 91818334Speter aname = NULL; 91918334Speter anamelen = 0; 92018334Speter for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++) 92118334Speter if(fname[fnamelen] == ':') { 92218334Speter aname = fname + fnamelen + 1; 92318334Speter anamelen = cnp->cn_namelen - fnamelen - 1; 92418334Speter dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n", 92518334Speter fname, fnamelen, aname, anamelen)); 92618334Speter break; 92718334Speter } 92818334Speter 92950397Sobrien dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %d\n", blsize, rdsize)); 93018334Speter 93118334Speter MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK); 93218334Speter 93318334Speter error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30", 93418334Speter 0, rdsize, rdbuf, NULL); 93518334Speter if (error) 93618334Speter goto fail; 93718334Speter 93818334Speter aoff = sizeof(struct attr_indexroot); 93918334Speter 94018334Speter do { 94118334Speter iep = (struct attr_indexentry *) (rdbuf + aoff); 94218334Speter 94318334Speter for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 94418334Speter aoff += iep->reclen, 94518334Speter iep = (struct attr_indexentry *) (rdbuf + aoff)) 94618334Speter { 94718334Speter ddprintf(("scan: %d, %d\n", 94818334Speter (u_int32_t) iep->ie_number, 94918334Speter (u_int32_t) iep->ie_fnametype)); 95018334Speter 95118334Speter /* check the name - the case-insensitible check 95218334Speter * has to come first, to break from this for loop 95318334Speter * if needed, so we can dive correctly */ 95418334Speter res = NTFS_UASTRICMP(iep->ie_fname, iep->ie_fnamelen, 95518334Speter fname, fnamelen); 95618334Speter if (res > 0) break; 95718334Speter if (res < 0) continue; 95818334Speter 95950397Sobrien if (iep->ie_fnametype == 0 || 96018334Speter !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS)) 96118334Speter { 96218334Speter res = NTFS_UASTRCMP(iep->ie_fname, 96318334Speter iep->ie_fnamelen, fname, fnamelen); 96418334Speter if (res != 0) continue; 96518334Speter } 96650397Sobrien 96718334Speter if (aname) { 96850397Sobrien error = ntfs_ntlookupattr(ntmp, 96918334Speter aname, anamelen, 97018334Speter &attrtype, &attrname); 97118334Speter if (error) 97218334Speter goto fail; 97318334Speter } 97418334Speter 97518334Speter /* Check if we've found ourself */ 97618334Speter if ((iep->ie_number == ip->i_number) && 97718334Speter (attrtype == fp->f_attrtype) && 97818334Speter ((!attrname && !fp->f_attrname) || 97918334Speter (attrname && fp->f_attrname && 98018334Speter !strcmp(attrname, fp->f_attrname)))) 98118334Speter { 98218334Speter VREF(vp); 98318334Speter *vpp = vp; 98418334Speter error = 0; 98518334Speter goto fail; 98618334Speter } 98718334Speter 98818334Speter /* vget node, but don't load it */ 98918334Speter error = ntfs_vgetex(ntmp->ntm_mountp, 99018334Speter iep->ie_number, attrtype, attrname, 99118334Speter LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN, 99218334Speter curthread, &nvp); 99318334Speter 99418334Speter /* free the buffer returned by ntfs_ntlookupattr() */ 99518334Speter if (attrname) { 99618334Speter FREE(attrname, M_TEMP); 99718334Speter attrname = NULL; 99818334Speter } 99918334Speter 100018334Speter if (error) 100118334Speter goto fail; 100218334Speter 100318334Speter nfp = VTOF(nvp); 100418334Speter 100518334Speter if (nfp->f_flag & FN_VALID) { 100618334Speter *vpp = nvp; 100718334Speter goto fail; 100818334Speter } 100918334Speter 101018334Speter nfp->f_fflag = iep->ie_fflag; 101118334Speter nfp->f_pnumber = iep->ie_fpnumber; 101218334Speter nfp->f_times = iep->ie_ftimes; 101318334Speter 101418334Speter if((nfp->f_fflag & NTFS_FFLAG_DIR) && 101518334Speter (nfp->f_attrtype == NTFS_A_DATA) && 101618334Speter (nfp->f_attrname == NULL)) 101718334Speter f_type = VDIR; 101818334Speter else 101918334Speter f_type = VREG; 102018334Speter 102118334Speter nvp->v_type = f_type; 102218334Speter 102318334Speter if ((nfp->f_attrtype == NTFS_A_DATA) && 102418334Speter (nfp->f_attrname == NULL)) 102518334Speter { 102650397Sobrien /* Opening default attribute */ 102750397Sobrien nfp->f_size = iep->ie_fsize; 102818334Speter nfp->f_allocated = iep->ie_fallocated; 102918334Speter nfp->f_flag |= FN_PRELOADED; 103018334Speter } else { 103118334Speter error = ntfs_filesize(ntmp, nfp, 103250397Sobrien &nfp->f_size, &nfp->f_allocated); 103350397Sobrien if (error) { 103450397Sobrien vput(nvp); 103550397Sobrien goto fail; 103650397Sobrien } 103750397Sobrien } 103850397Sobrien 103950397Sobrien nfp->f_flag &= ~FN_VALID; 104050397Sobrien *vpp = nvp; 104150397Sobrien goto fail; 104250397Sobrien } 104350397Sobrien 104450397Sobrien /* Dive if possible */ 104550397Sobrien if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) { 104650397Sobrien dprintf(("ntfs_ntlookupfile: diving\n")); 104750397Sobrien 104850397Sobrien cn = *(cn_t *) (rdbuf + aoff + 104950397Sobrien iep->reclen - sizeof(cn_t)); 105018334Speter rdsize = blsize; 105118334Speter 105218334Speter error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30", 105318334Speter ntfs_cntob(cn), rdsize, rdbuf, NULL); 105418334Speter if (error) 105518334Speter goto fail; 105618334Speter 105718334Speter error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 105818334Speter rdbuf, rdsize); 105918334Speter if (error) 106018334Speter goto fail; 106118334Speter 106218334Speter aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize + 106318334Speter 0x18); 106418334Speter } else { 106518334Speter dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n")); 106618334Speter error = ENOENT; 106718334Speter break; 106818334Speter } 106918334Speter } while (1); 107018334Speter 107118334Speter dprintf(("finish\n")); 107218334Speter 107318334Speterfail: 107418334Speter if (attrname) FREE(attrname, M_TEMP); 107518334Speter ntfs_ntvattrrele(vap); 107618334Speter ntfs_ntput(ip); 107718334Speter FREE(rdbuf, M_TEMP); 107818334Speter return (error); 107918334Speter} 108018334Speter 108118334Speter/* 108218334Speter * Check if name type is permitted to show. 108318334Speter */ 108418334Speterint 108518334Speterntfs_isnamepermitted( 108618334Speter struct ntfsmount * ntmp, 108718334Speter struct attr_indexentry * iep) 108818334Speter{ 108918334Speter if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) 109018334Speter return 1; 109118334Speter 109218334Speter switch (iep->ie_fnametype) { 109318334Speter case 2: 109418334Speter ddprintf(("ntfs_isnamepermitted: skiped DOS name\n")); 109518334Speter return 0; 109618334Speter case 0: case 1: case 3: 109718334Speter return 1; 109818334Speter default: 109918334Speter printf("ntfs_isnamepermitted: " \ 110018334Speter "WARNING! Unknown file name type: %d\n", 110118334Speter iep->ie_fnametype); 110218334Speter break; 110318334Speter } 110450397Sobrien return 0; 110518334Speter} 110618334Speter 110718334Speter/* 110818334Speter * Read ntfs dir like stream of attr_indexentry, not like btree of them. 110918334Speter * This is done by scaning $BITMAP:$I30 for busy clusters and reading them. 111018334Speter * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in 111118334Speter * fnode, so we can skip toward record number num almost immediatly. 111218334Speter * Anyway this is rather slow routine. The problem is that we don't know 111318334Speter * how many records are there in $INDEX_ALLOCATION:$I30 block. 111418334Speter */ 111518334Speterint 111618334Speterntfs_ntreaddir( 111718334Speter struct ntfsmount * ntmp, 111818334Speter struct fnode * fp, 111918334Speter u_int32_t num, 112018334Speter struct attr_indexentry ** riepp) 112118334Speter{ 112218334Speter struct ntnode *ip = FTONT(fp); 112318334Speter struct ntvattr *vap = NULL; /* IndexRoot attribute */ 112418334Speter struct ntvattr *bmvap = NULL; /* BitMap attribute */ 112518334Speter struct ntvattr *iavap = NULL; /* IndexAllocation attribute */ 112618334Speter caddr_t rdbuf; /* Buffer to read directory's blocks */ 112718334Speter u_char *bmp = NULL; /* Bitmap */ 112818334Speter u_int32_t blsize; /* Index allocation size (2048) */ 112918334Speter u_int32_t rdsize; /* Length of data to read */ 113018334Speter u_int32_t attrnum; /* Current attribute type */ 113118334Speter u_int32_t cpbl = 1; /* Clusters per directory block */ 113218334Speter u_int32_t blnum; 113318334Speter struct attr_indexentry *iep; 113418334Speter int error = ENOENT; 113518334Speter u_int32_t aoff, cnum; 113618334Speter 113718334Speter dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num)); 113818334Speter error = ntfs_ntget(ip); 113918334Speter if (error) 114018334Speter return (error); 114118334Speter 114218334Speter error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 114318334Speter if (error) 114418334Speter return (ENOTDIR); 114518334Speter 114618334Speter if (fp->f_dirblbuf == NULL) { 114718334Speter fp->f_dirblsz = vap->va_a_iroot->ir_size; 114818334Speter MALLOC(fp->f_dirblbuf, caddr_t, 114918334Speter max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK); 115018334Speter } 115118334Speter 115218334Speter blsize = fp->f_dirblsz; 115318334Speter rdbuf = fp->f_dirblbuf; 115418334Speter 115518334Speter dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize)); 115618334Speter 115718334Speter if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) { 115818334Speter error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 115918334Speter 0, &bmvap); 116018334Speter if (error) { 116118334Speter error = ENOTDIR; 116218334Speter goto fail; 116318334Speter } 116418334Speter MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK); 116518334Speter error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0, 116618334Speter bmvap->va_datalen, bmp, NULL); 116718334Speter if (error) 116818334Speter goto fail; 116918334Speter 117050397Sobrien error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30", 117118334Speter 0, &iavap); 117218334Speter if (error) { 117350397Sobrien error = ENOTDIR; 117450397Sobrien goto fail; 117550397Sobrien } 117650397Sobrien cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1); 117718334Speter dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n", 117818334Speter iavap->va_datalen, cpbl)); 117918334Speter } else { 118018334Speter dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n")); 118118334Speter iavap = bmvap = NULL; 118218334Speter bmp = NULL; 118318334Speter } 118418334Speter 118518334Speter /* Try use previous values */ 118618334Speter if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) { 118718334Speter attrnum = fp->f_lastdattr; 118818334Speter aoff = fp->f_lastdoff; 118918334Speter blnum = fp->f_lastdblnum; 119018334Speter cnum = fp->f_lastdnum; 119118334Speter } else { 119218334Speter attrnum = NTFS_A_INDXROOT; 119318334Speter aoff = sizeof(struct attr_indexroot); 119418334Speter blnum = 0; 119518334Speter cnum = 0; 119618334Speter } 119718334Speter 119818334Speter do { 119918334Speter dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n", 120018334Speter attrnum, (u_int32_t) blnum, cnum, num, aoff)); 120118334Speter rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize; 120218334Speter error = ntfs_readattr(ntmp, ip, attrnum, "$I30", 120318334Speter ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL); 120418334Speter if (error) 120518334Speter goto fail; 120618334Speter 120718334Speter if (attrnum == NTFS_A_INDX) { 120818334Speter error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 120918334Speter rdbuf, rdsize); 121018334Speter if (error) 121118334Speter goto fail; 121250397Sobrien } 121350397Sobrien if (aoff == 0) 121450397Sobrien aoff = (attrnum == NTFS_A_INDX) ? 121550397Sobrien (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) : 121650397Sobrien sizeof(struct attr_indexroot); 121750397Sobrien 121818334Speter iep = (struct attr_indexentry *) (rdbuf + aoff); 121918334Speter for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 122018334Speter aoff += iep->reclen, 122118334Speter iep = (struct attr_indexentry *) (rdbuf + aoff)) 122218334Speter { 122318334Speter if (!ntfs_isnamepermitted(ntmp, iep)) continue; 122418334Speter 122518334Speter if (cnum >= num) { 122618334Speter fp->f_lastdnum = cnum; 122718334Speter fp->f_lastdoff = aoff; 122818334Speter fp->f_lastdblnum = blnum; 122918334Speter fp->f_lastdattr = attrnum; 123018334Speter 123118334Speter *riepp = iep; 123218334Speter 123318334Speter error = 0; 123418334Speter goto fail; 123518334Speter } 123618334Speter cnum++; 123718334Speter } 123818334Speter 123918334Speter if (iavap) { 124018334Speter if (attrnum == NTFS_A_INDXROOT) 124118334Speter blnum = 0; 124218334Speter else 124318334Speter blnum++; 124418334Speter 124518334Speter while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) { 124618334Speter if (bmp[blnum >> 3] & (1 << (blnum & 3))) 124718334Speter break; 124818334Speter blnum++; 124918334Speter } 125018334Speter 125118334Speter attrnum = NTFS_A_INDX; 125218334Speter aoff = 0; 125318334Speter if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen) 125418334Speter break; 125518334Speter dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum)); 125618334Speter } 125718334Speter } while (iavap); 125818334Speter 125918334Speter *riepp = NULL; 126018334Speter fp->f_lastdnum = 0; 126150397Sobrien 126250397Sobrienfail: 126350397Sobrien if (vap) 126418334Speter ntfs_ntvattrrele(vap); 126518334Speter if (bmvap) 126618334Speter ntfs_ntvattrrele(bmvap); 126718334Speter if (iavap) 126818334Speter ntfs_ntvattrrele(iavap); 126918334Speter if (bmp) 127018334Speter FREE(bmp, M_TEMP); 127118334Speter ntfs_ntput(ip); 127218334Speter return (error); 127318334Speter} 127418334Speter 127518334Speter/* 127618334Speter * Convert NTFS times that are in 100 ns units and begins from 127718334Speter * 1601 Jan 1 into unix times. 127818334Speter */ 127918334Speterstruct timespec 128018334Speterntfs_nttimetounix( 128118334Speter u_int64_t nt) 128218334Speter{ 128318334Speter struct timespec t; 128418334Speter 128518334Speter /* WindowNT times are in 100 ns and from 1601 Jan 1 */ 128618334Speter t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100; 128718334Speter t.tv_sec = nt / (1000 * 1000 * 10) - 128818334Speter 369LL * 365LL * 24LL * 60LL * 60LL - 128918334Speter 89LL * 1LL * 24LL * 60LL * 60LL; 129018334Speter return (t); 129118334Speter} 129218334Speter 129318334Speter/* 129418334Speter * Get file times from NTFS_A_NAME attribute. 129518334Speter */ 129618334Speterint 129718334Speterntfs_times( 129818334Speter struct ntfsmount * ntmp, 129918334Speter struct ntnode * ip, 130018334Speter ntfs_times_t * tm) 130118334Speter{ 130218334Speter struct ntvattr *vap; 130318334Speter int error; 130418334Speter 130518334Speter dprintf(("ntfs_times: ino: %d...\n", ip->i_number)); 130618334Speter 130718334Speter error = ntfs_ntget(ip); 130818334Speter if (error) 130918334Speter return (error); 131018334Speter 131118334Speter error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap); 131218334Speter if (error) { 131318334Speter ntfs_ntput(ip); 131418334Speter return (error); 131518334Speter } 131618334Speter *tm = vap->va_a_name->n_times; 131718334Speter ntfs_ntvattrrele(vap); 131818334Speter ntfs_ntput(ip); 131918334Speter 132018334Speter return (0); 132118334Speter} 132218334Speter 132318334Speter/* 132418334Speter * Get file sizes from corresponding attribute. 132518334Speter * 132618334Speter * ntnode under fnode should be locked. 132718334Speter */ 132818334Speterint 132918334Speterntfs_filesize( 133018334Speter struct ntfsmount * ntmp, 133118334Speter struct fnode * fp, 133218334Speter u_int64_t * size, 133318334Speter u_int64_t * bytes) 133418334Speter{ 133518334Speter struct ntvattr *vap; 133618334Speter struct ntnode *ip = FTONT(fp); 133718334Speter u_int64_t sz, bn; 133818334Speter int error; 133918334Speter 134018334Speter dprintf(("ntfs_filesize: ino: %d\n", ip->i_number)); 134118334Speter 134218334Speter error = ntfs_ntvattrget(ntmp, ip, 134318334Speter fp->f_attrtype, fp->f_attrname, 0, &vap); 134418334Speter if (error) 134518334Speter return (error); 134618334Speter 134718334Speter bn = vap->va_allocated; 134818334Speter sz = vap->va_datalen; 134918334Speter 135050397Sobrien dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n", 135118334Speter (u_int32_t) sz, (u_int32_t) bn)); 135218334Speter 135318334Speter if (size) 135418334Speter *size = sz; 135518334Speter if (bytes) 135618334Speter *bytes = bn; 135718334Speter 135818334Speter ntfs_ntvattrrele(vap); 135918334Speter 136018334Speter return (0); 136118334Speter} 136218334Speter 136318334Speter/* 136418334Speter * This is one of write routine. 136518334Speter */ 136618334Speterint 136718334Speterntfs_writeattr_plain( 136818334Speter struct ntfsmount * ntmp, 136918334Speter struct ntnode * ip, 137018334Speter u_int32_t attrnum, 137118334Speter char *attrname, 137218334Speter off_t roff, 137318334Speter size_t rsize, 137418334Speter void *rdata, 137518334Speter size_t * initp, 137618334Speter struct uio *uio) 137718334Speter{ 137818334Speter size_t init; 137918334Speter int error = 0; 138018334Speter off_t off = roff, left = rsize, towrite; 138118334Speter caddr_t data = rdata; 138218334Speter struct ntvattr *vap; 138318334Speter *initp = 0; 138418334Speter 138518334Speter while (left) { 138618334Speter error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 138718334Speter ntfs_btocn(off), &vap); 138818334Speter if (error) 138918334Speter return (error); 139018334Speter towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off); 139118334Speter ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n", 139218334Speter (u_int32_t) off, (u_int32_t) towrite, 139318334Speter (u_int32_t) vap->va_vcnstart, 139418334Speter (u_int32_t) vap->va_vcnend)); 139518334Speter error = ntfs_writentvattr_plain(ntmp, ip, vap, 139618334Speter off - ntfs_cntob(vap->va_vcnstart), 139718334Speter towrite, data, &init, uio); 139818334Speter if (error) { 139918334Speter printf("ntfs_writeattr_plain: " \ 140018334Speter "ntfs_writentvattr_plain failed: o: %d, s: %d\n", 140118334Speter (u_int32_t) off, (u_int32_t) towrite); 140218334Speter printf("ntfs_writeattr_plain: attrib: %d - %d\n", 140318334Speter (u_int32_t) vap->va_vcnstart, 140418334Speter (u_int32_t) vap->va_vcnend); 140518334Speter ntfs_ntvattrrele(vap); 140618334Speter break; 140718334Speter } 140818334Speter ntfs_ntvattrrele(vap); 140918334Speter left -= towrite; 141018334Speter off += towrite; 141118334Speter data = data + towrite; 141218334Speter *initp += init; 141318334Speter } 141418334Speter 141518334Speter return (error); 141618334Speter} 141718334Speter 141818334Speter/* 141918334Speter * This is one of write routine. 142018334Speter * 142118334Speter * ntnode should be locked. 142218334Speter */ 142318334Speterint 142418334Speterntfs_writentvattr_plain( 142518334Speter struct ntfsmount * ntmp, 142618334Speter struct ntnode * ip, 142718334Speter struct ntvattr * vap, 142818334Speter off_t roff, 142918334Speter size_t rsize, 143018334Speter void *rdata, 143118334Speter size_t * initp, 143218334Speter struct uio *uio) 143318334Speter{ 143418334Speter int error = 0; 143518334Speter int off; 143618334Speter int cnt; 143718334Speter cn_t ccn, ccl, cn, left, cl; 143818334Speter caddr_t data = rdata; 143918334Speter struct buf *bp; 144018334Speter size_t tocopy; 144118334Speter 144218334Speter *initp = 0; 144318334Speter 144418334Speter if ((vap->va_flag & NTFS_AF_INRUN) == 0) { 144518334Speter printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n"); 144618334Speter return ENOTTY; 144718334Speter } 144818334Speter 144918334Speter ddprintf(("ntfs_writentvattr_plain: data in run: %ld chains\n", 145018334Speter vap->va_vruncnt)); 145118334Speter 145218334Speter off = roff; 145318334Speter left = rsize; 145418334Speter ccl = 0; 145518334Speter ccn = 0; 145618334Speter cnt = 0; 145718334Speter for (; left && (cnt < vap->va_vruncnt); cnt++) { 145818334Speter ccn = vap->va_vruncn[cnt]; 145918334Speter ccl = vap->va_vruncl[cnt]; 146018334Speter 146118334Speter ddprintf(("ntfs_writentvattr_plain: " \ 146218334Speter "left %d, cn: 0x%x, cl: %d, off: %d\n", \ 146318334Speter (u_int32_t) left, (u_int32_t) ccn, \ 146418334Speter (u_int32_t) ccl, (u_int32_t) off)); 146518334Speter 146618334Speter if (ntfs_cntob(ccl) < off) { 146718334Speter off -= ntfs_cntob(ccl); 146818334Speter cnt++; 146918334Speter continue; 147018334Speter } 147118334Speter if (!ccn && ip->i_number != NTFS_BOOTINO) 147218334Speter continue; /* XXX */ 147318334Speter 147418334Speter ccl -= ntfs_btocn(off); 147518334Speter cn = ccn + ntfs_btocn(off); 147618334Speter off = ntfs_btocnoff(off); 147718334Speter 147818334Speter while (left && ccl) { 147918334Speter /* 148018334Speter * Always read and write single clusters at a time - 148118334Speter * we need to avoid requesting differently-sized 148218334Speter * blocks at the same disk offsets to avoid 148318334Speter * confusing the buffer cache. 148450397Sobrien */ 148550397Sobrien tocopy = min(left, ntfs_cntob(1) - off); 148650397Sobrien cl = ntfs_btocl(tocopy + off); 148750397Sobrien KASSERT(cl == 1 && tocopy <= ntfs_cntob(1), 148850397Sobrien ("single cluster limit mistake")); 148950397Sobrien ddprintf(("ntfs_writentvattr_plain: write: " \ 149050397Sobrien "cn: 0x%x cl: %d, off: %d len: %d, left: %d\n", 149150397Sobrien (u_int32_t) cn, (u_int32_t) cl, 149218334Speter (u_int32_t) off, (u_int32_t) tocopy, 149318334Speter (u_int32_t) left)); 149418334Speter if ((off == 0) && (tocopy == ntfs_cntob(cl))) 149518334Speter { 149618334Speter bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn), 149718334Speter ntfs_cntob(cl), 0, 0, 0); 149818334Speter clrbuf(bp); 149918334Speter } else { 150018334Speter error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn), 150118334Speter ntfs_cntob(cl), NOCRED, &bp); 150218334Speter if (error) { 150350397Sobrien brelse(bp); 150450397Sobrien return (error); 150518334Speter } 150618334Speter } 150718334Speter if (uio) 150818334Speter uiomove(bp->b_data + off, tocopy, uio); 150918334Speter else 151018334Speter memcpy(bp->b_data + off, data, tocopy); 151118334Speter bawrite(bp); 151218334Speter data = data + tocopy; 151318334Speter *initp += tocopy; 151418334Speter off = 0; 151518334Speter left -= tocopy; 151618334Speter cn += cl; 151718334Speter ccl -= cl; 151818334Speter } 151918334Speter } 152018334Speter 152118334Speter if (left) { 152218334Speter printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n"); 152318334Speter error = EINVAL; 152418334Speter } 152518334Speter 152618334Speter return (error); 152718334Speter} 152818334Speter 152918334Speter/* 153018334Speter * This is one of read routines. 153118334Speter * 153218334Speter * ntnode should be locked. 153318334Speter */ 153418334Speterint 153518334Speterntfs_readntvattr_plain( 153618334Speter struct ntfsmount * ntmp, 153718334Speter struct ntnode * ip, 153818334Speter struct ntvattr * vap, 153918334Speter off_t roff, 154018334Speter size_t rsize, 154118334Speter void *rdata, 154218334Speter size_t * initp, 154318334Speter struct uio *uio) 154418334Speter{ 154518334Speter int error = 0; 154618334Speter int off; 154718334Speter 154818334Speter *initp = 0; 154918334Speter if (vap->va_flag & NTFS_AF_INRUN) { 155018334Speter int cnt; 155118334Speter cn_t ccn, ccl, cn, left, cl; 155218334Speter caddr_t data = rdata; 155318334Speter struct buf *bp; 155418334Speter size_t tocopy; 155518334Speter 155618334Speter ddprintf(("ntfs_readntvattr_plain: data in run: %ld chains\n", 155718334Speter vap->va_vruncnt)); 155818334Speter 155918334Speter off = roff; 156018334Speter left = rsize; 156118334Speter ccl = 0; 156218334Speter ccn = 0; 156318334Speter cnt = 0; 156418334Speter while (left && (cnt < vap->va_vruncnt)) { 156518334Speter ccn = vap->va_vruncn[cnt]; 156618334Speter ccl = vap->va_vruncl[cnt]; 156718334Speter 156818334Speter ddprintf(("ntfs_readntvattr_plain: " \ 156918334Speter "left %d, cn: 0x%x, cl: %d, off: %d\n", \ 157018334Speter (u_int32_t) left, (u_int32_t) ccn, \ 157118334Speter (u_int32_t) ccl, (u_int32_t) off)); 157218334Speter 157318334Speter if (ntfs_cntob(ccl) < off) { 157418334Speter off -= ntfs_cntob(ccl); 157518334Speter cnt++; 157618334Speter continue; 157718334Speter } 157818334Speter if (ccn || ip->i_number == NTFS_BOOTINO) { 157918334Speter ccl -= ntfs_btocn(off); 158018334Speter cn = ccn + ntfs_btocn(off); 158118334Speter off = ntfs_btocnoff(off); 158218334Speter 158318334Speter while (left && ccl) { 158418334Speter /* 158518334Speter * Always read single clusters at a 158618334Speter * time - we need to avoid reading 158718334Speter * differently-sized blocks at the 158818334Speter * same disk offsets to avoid 158918334Speter * confusing the buffer cache. 159018334Speter */ 159118334Speter tocopy = min(left, 159218334Speter ntfs_cntob(1) - off); 159318334Speter cl = ntfs_btocl(tocopy + off); 159418334Speter KASSERT(cl == 1 && 159550397Sobrien tocopy <= ntfs_cntob(1), 159650397Sobrien ("single cluster limit mistake")); 159718334Speter 159818334Speter ddprintf(("ntfs_readntvattr_plain: " \ 159918334Speter "read: cn: 0x%x cl: %d, " \ 160018334Speter "off: %d len: %d, left: %d\n", 160118334Speter (u_int32_t) cn, 160218334Speter (u_int32_t) cl, 160318334Speter (u_int32_t) off, 160418334Speter (u_int32_t) tocopy, 160518334Speter (u_int32_t) left)); 160618334Speter error = bread(ntmp->ntm_devvp, 160718334Speter ntfs_cntobn(cn), 160818334Speter ntfs_cntob(cl), 160918334Speter NOCRED, &bp); 161018334Speter if (error) { 161118334Speter brelse(bp); 161218334Speter return (error); 161318334Speter } 161418334Speter if (uio) { 161518334Speter uiomove(bp->b_data + off, 161618334Speter tocopy, uio); 161718334Speter } else { 161818334Speter memcpy(data, bp->b_data + off, 161918334Speter tocopy); 162018334Speter } 162118334Speter brelse(bp); 162218334Speter data = data + tocopy; 162318334Speter *initp += tocopy; 162418334Speter off = 0; 162518334Speter left -= tocopy; 162618334Speter cn += cl; 162718334Speter ccl -= cl; 162818334Speter } 162918334Speter } else { 163018334Speter tocopy = min(left, ntfs_cntob(ccl) - off); 163118334Speter ddprintf(("ntfs_readntvattr_plain: " 163218334Speter "hole: ccn: 0x%x ccl: %d, off: %d, " \ 163318334Speter " len: %d, left: %d\n", 163418334Speter (u_int32_t) ccn, (u_int32_t) ccl, 163518334Speter (u_int32_t) off, (u_int32_t) tocopy, 163618334Speter (u_int32_t) left)); 163718334Speter left -= tocopy; 163818334Speter off = 0; 163918334Speter if (uio) { 164018334Speter size_t remains = tocopy; 164118334Speter for(; remains; remains--) 164218334Speter uiomove("", 1, uio); 164318334Speter } else 164418334Speter bzero(data, tocopy); 164518334Speter data = data + tocopy; 164618334Speter } 164718334Speter cnt++; 164818334Speter } 164918334Speter if (left) { 165018334Speter printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n"); 165118334Speter error = E2BIG; 165218334Speter } 165318334Speter } else { 165418334Speter ddprintf(("ntfs_readnvattr_plain: data is in mft record\n")); 165518334Speter if (uio) 165618334Speter uiomove(vap->va_datap + roff, rsize, uio); 165718334Speter else 165818334Speter memcpy(rdata, vap->va_datap + roff, rsize); 165918334Speter *initp += rsize; 166018334Speter } 166118334Speter 166218334Speter return (error); 166318334Speter} 166418334Speter 166518334Speter/* 166618334Speter * This is one of read routines. 166718334Speter */ 166818334Speterint 166918334Speterntfs_readattr_plain( 167018334Speter struct ntfsmount * ntmp, 167118334Speter struct ntnode * ip, 167218334Speter u_int32_t attrnum, 167318334Speter char *attrname, 167418334Speter off_t roff, 167518334Speter size_t rsize, 167618334Speter void *rdata, 167718334Speter size_t * initp, 167818334Speter struct uio *uio) 167918334Speter{ 168018334Speter size_t init; 168118334Speter int error = 0; 168218334Speter off_t off = roff, left = rsize, toread; 168318334Speter caddr_t data = rdata; 168418334Speter struct ntvattr *vap; 168518334Speter *initp = 0; 168618334Speter 168718334Speter while (left) { 168818334Speter error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 168918334Speter ntfs_btocn(off), &vap); 169018334Speter if (error) 169118334Speter return (error); 169218334Speter toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off); 169318334Speter ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n", 169418334Speter (u_int32_t) off, (u_int32_t) toread, 169518334Speter (u_int32_t) vap->va_vcnstart, 169618334Speter (u_int32_t) vap->va_vcnend)); 169718334Speter error = ntfs_readntvattr_plain(ntmp, ip, vap, 169818334Speter off - ntfs_cntob(vap->va_vcnstart), 169918334Speter toread, data, &init, uio); 170018334Speter if (error) { 170118334Speter printf("ntfs_readattr_plain: " \ 170218334Speter "ntfs_readntvattr_plain failed: o: %d, s: %d\n", 170318334Speter (u_int32_t) off, (u_int32_t) toread); 170418334Speter printf("ntfs_readattr_plain: attrib: %d - %d\n", 170518334Speter (u_int32_t) vap->va_vcnstart, 170618334Speter (u_int32_t) vap->va_vcnend); 170718334Speter ntfs_ntvattrrele(vap); 170818334Speter break; 170918334Speter } 171018334Speter ntfs_ntvattrrele(vap); 171118334Speter left -= toread; 171218334Speter off += toread; 171318334Speter data = data + toread; 171418334Speter *initp += init; 171518334Speter } 171618334Speter 171718334Speter return (error); 171818334Speter} 171918334Speter 172018334Speter/* 172118334Speter * This is one of read routines. 172218334Speter */ 172318334Speterint 172418334Speterntfs_readattr( 172518334Speter struct ntfsmount * ntmp, 172618334Speter struct ntnode * ip, 172718334Speter u_int32_t attrnum, 172818334Speter char *attrname, 172918334Speter off_t roff, 173018334Speter size_t rsize, 173118334Speter void *rdata, 173218334Speter struct uio *uio) 173318334Speter{ 173418334Speter int error = 0; 173518334Speter struct ntvattr *vap; 173618334Speter size_t init; 173718334Speter 173818334Speter ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n", 173918334Speter ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize)); 174018334Speter 174118334Speter error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap); 174218334Speter if (error) 174318334Speter return (error); 174418334Speter 174518334Speter if ((roff > vap->va_datalen) || 174618334Speter (roff + rsize > vap->va_datalen)) { 174718334Speter ddprintf(("ntfs_readattr: offset too big\n")); 174818334Speter ntfs_ntvattrrele(vap); 174918334Speter return (E2BIG); 175018334Speter } 175118334Speter if (vap->va_compression && vap->va_compressalg) { 175218334Speter u_int8_t *cup; 175318334Speter u_int8_t *uup; 175418334Speter off_t off = roff, left = rsize, tocopy; 175518334Speter caddr_t data = rdata; 175618334Speter cn_t cn; 175718334Speter 175818334Speter ddprintf(("ntfs_ntreadattr: compression: %d\n", 175918334Speter vap->va_compressalg)); 176018334Speter 176118334Speter MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL), 176218334Speter M_NTFSDECOMP, M_WAITOK); 176318334Speter MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL), 176450397Sobrien M_NTFSDECOMP, M_WAITOK); 176518334Speter 176618334Speter cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1)); 176718334Speter off = roff - ntfs_cntob(cn); 176818334Speter 176918334Speter while (left) { 177018334Speter error = ntfs_readattr_plain(ntmp, ip, attrnum, 177118334Speter attrname, ntfs_cntob(cn), 177218334Speter ntfs_cntob(NTFS_COMPUNIT_CL), 177318334Speter cup, &init, NULL); 177418334Speter if (error) 177518334Speter break; 177618334Speter 177718334Speter tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off); 177818334Speter 177918334Speter if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) { 178018334Speter if (uio) 178118334Speter uiomove(cup + off, tocopy, uio); 178218334Speter else 178318334Speter memcpy(data, cup + off, tocopy); 178418334Speter } else if (init == 0) { 178518334Speter if (uio) { 178618334Speter size_t remains = tocopy; 178718334Speter for(; remains; remains--) 178818334Speter uiomove("", 1, uio); 178918334Speter } 179018334Speter else 179118334Speter bzero(data, tocopy); 179218334Speter } else { 179318334Speter error = ntfs_uncompunit(ntmp, uup, cup); 179418334Speter if (error) 179518334Speter break; 179618334Speter if (uio) 179718334Speter uiomove(uup + off, tocopy, uio); 179818334Speter else 179918334Speter memcpy(data, uup + off, tocopy); 180018334Speter } 180118334Speter 180218334Speter left -= tocopy; 180318334Speter data = data + tocopy; 180418334Speter off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL); 180518334Speter cn += NTFS_COMPUNIT_CL; 180618334Speter } 180718334Speter 180818334Speter FREE(uup, M_NTFSDECOMP); 180918334Speter FREE(cup, M_NTFSDECOMP); 181018334Speter } else 181118334Speter error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname, 181218334Speter roff, rsize, rdata, &init, uio); 181318334Speter ntfs_ntvattrrele(vap); 181418334Speter return (error); 181518334Speter} 181618334Speter 181718334Speter#if UNUSED_CODE 181818334Speterint 181918334Speterntfs_parserun( 182018334Speter cn_t * cn, 182118334Speter cn_t * cl, 182218334Speter u_int8_t * run, 182318334Speter u_long len, 182418334Speter u_long *off) 182518334Speter{ 182618334Speter u_int8_t sz; 182718334Speter int i; 182818334Speter 182918334Speter if (NULL == run) { 183018334Speter printf("ntfs_parsetun: run == NULL\n"); 183118334Speter return (EINVAL); 183218334Speter } 183318334Speter sz = run[(*off)++]; 183418334Speter if (0 == sz) { 183518334Speter printf("ntfs_parserun: trying to go out of run\n"); 183618334Speter return (E2BIG); 183718334Speter } 183818334Speter *cl = 0; 183918334Speter if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 184018334Speter printf("ntfs_parserun: " \ 184118334Speter "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 184218334Speter sz, len, *off); 184318334Speter return (EINVAL); 184418334Speter } 184518334Speter for (i = 0; i < (sz & 0xF); i++) 184618334Speter *cl += (u_int32_t) run[(*off)++] << (i << 3); 184718334Speter 184818334Speter sz >>= 4; 184918334Speter if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 185018334Speter printf("ntfs_parserun: " \ 185118334Speter "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 185218334Speter sz, len, *off); 185318334Speter return (EINVAL); 185418334Speter } 185518334Speter for (i = 0; i < (sz & 0xF); i++) 185618334Speter *cn += (u_int32_t) run[(*off)++] << (i << 3); 185718334Speter 185818334Speter return (0); 185918334Speter} 186018334Speter#endif 186118334Speter 186218334Speter/* 186318334Speter * Process fixup routine on given buffer. 186418334Speter */ 186518334Speterint 186618334Speterntfs_procfixups( 186718334Speter struct ntfsmount * ntmp, 186818334Speter u_int32_t magic, 186918334Speter caddr_t buf, 187018334Speter size_t len) 187118334Speter{ 187218334Speter struct fixuphdr *fhp = (struct fixuphdr *) buf; 187318334Speter int i; 187418334Speter u_int16_t fixup; 187518334Speter u_int16_t *fxp; 187618334Speter u_int16_t *cfxp; 187718334Speter 187818334Speter if (fhp->fh_magic != magic) { 187918334Speter printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n", 188018334Speter fhp->fh_magic, magic); 188118334Speter return (EINVAL); 188218334Speter } 188318334Speter if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) { 188418334Speter printf("ntfs_procfixups: " \ 188518334Speter "bad fixups number: %d for %ld bytes block\n", 188618334Speter fhp->fh_fnum, (long)len); /* XXX printf kludge */ 188718334Speter return (EINVAL); 188818334Speter } 188918334Speter if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) { 189018334Speter printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff); 189118334Speter return (EINVAL); 189218334Speter } 189318334Speter fxp = (u_int16_t *) (buf + fhp->fh_foff); 189418334Speter cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2); 189518334Speter fixup = *fxp++; 189618334Speter for (i = 1; i < fhp->fh_fnum; i++, fxp++) { 189718334Speter if (*cfxp != fixup) { 189818334Speter printf("ntfs_procfixups: fixup %d doesn't match\n", i); 189918334Speter return (EINVAL); 190018334Speter } 190118334Speter *cfxp = *fxp; 190218334Speter ((caddr_t) cfxp) += ntmp->ntm_bps; 190318334Speter } 190418334Speter return (0); 190518334Speter} 190618334Speter 190718334Speter#if UNUSED_CODE 190818334Speterint 190918334Speterntfs_runtocn( 191018334Speter cn_t * cn, 191118334Speter struct ntfsmount * ntmp, 191218334Speter u_int8_t * run, 191318334Speter u_long len, 191418334Speter cn_t vcn) 191518334Speter{ 191618334Speter cn_t ccn = 0; 191718334Speter cn_t ccl = 0; 191818334Speter u_long off = 0; 191918334Speter int error = 0; 192018334Speter 192118334Speter#if NTFS_DEBUG 192218334Speter int i; 192318334Speter printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n", 192418334Speter run, len, (u_long) vcn); 192518334Speter printf("ntfs_runtocn: run: "); 192618334Speter for (i = 0; i < len; i++) 192718334Speter printf("0x%02x ", run[i]); 192818334Speter printf("\n"); 192918334Speter#endif 193018334Speter 193118334Speter if (NULL == run) { 193218334Speter printf("ntfs_runtocn: run == NULL\n"); 193318334Speter return (EINVAL); 193418334Speter } 193518334Speter do { 193618334Speter if (run[off] == 0) { 193718334Speter printf("ntfs_runtocn: vcn too big\n"); 193818334Speter return (E2BIG); 193918334Speter } 194018334Speter vcn -= ccl; 194118334Speter error = ntfs_parserun(&ccn, &ccl, run, len, &off); 194218334Speter if (error) { 194318334Speter printf("ntfs_runtocn: ntfs_parserun failed\n"); 194418334Speter return (error); 194518334Speter } 194618334Speter } while (ccl <= vcn); 194718334Speter *cn = ccn + vcn; 194818334Speter return (0); 194918334Speter} 195018334Speter#endif 195118334Speter 195218334Speter/* 195318334Speter * this initializes toupper table & dependant variables to be ready for 195418334Speter * later work 195518334Speter */ 195618334Spetervoid 195718334Speterntfs_toupper_init() 195818334Speter{ 195918334Speter ntfs_toupper_tab = (wchar *) NULL; 196018334Speter lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0); 196118334Speter ntfs_toupper_usecount = 0; 196218334Speter} 196318334Speter 196418334Spetervoid 196518334Speterntfs_toupper_destroy(void) 196618334Speter{ 196718334Speter 196818334Speter lockdestroy(&ntfs_toupper_lock); 196918334Speter} 197018334Speter 197118334Speter/* 197218334Speter * if the ntfs_toupper_tab[] is filled already, just raise use count; 197318334Speter * otherwise read the data from the filesystem we are currently mounting 197418334Speter */ 197518334Speterint 197618334Speterntfs_toupper_use(mp, ntmp) 197718334Speter struct mount *mp; 197818334Speter struct ntfsmount *ntmp; 197918334Speter{ 198018334Speter int error = 0; 198118334Speter struct vnode *vp; 198218334Speter 198318334Speter /* get exclusive access */ 198418334Speter lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL, NULL); 198518334Speter 198618334Speter /* only read the translation data from a file if it hasn't been 198718334Speter * read already */ 198818334Speter if (ntfs_toupper_tab) 198918334Speter goto out; 199018334Speter 199118334Speter /* 199218334Speter * Read in Unicode lowercase -> uppercase translation file. 199318334Speter * XXX for now, just the first 256 entries are used anyway, 199418334Speter * so don't bother reading more 199518334Speter */ 199618334Speter MALLOC(ntfs_toupper_tab, wchar *, 65536 * sizeof(wchar), 199718334Speter M_NTFSRDATA, M_WAITOK); 199818334Speter 199918334Speter if ((error = VFS_VGET(mp, NTFS_UPCASEINO, LK_EXCLUSIVE, &vp))) 200018334Speter goto out; 200118334Speter error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 200218334Speter 0, 65536*sizeof(wchar), (char *) ntfs_toupper_tab, NULL); 200318334Speter vput(vp); 200418334Speter 200518334Speter out: 200618334Speter ntfs_toupper_usecount++; 200718334Speter lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL, NULL); 200818334Speter return (error); 200918334Speter} 201018334Speter 201118334Speter/* 201218334Speter * lower the use count and if it reaches zero, free the memory 201318334Speter * tied by toupper table 201418334Speter */ 201518334Spetervoid 201618334Speterntfs_toupper_unuse() 201718334Speter{ 201818334Speter /* get exclusive access */ 201918334Speter lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL, NULL); 202018334Speter 202118334Speter ntfs_toupper_usecount--; 202218334Speter if (ntfs_toupper_usecount == 0) { 202318334Speter FREE(ntfs_toupper_tab, M_NTFSRDATA); 202418334Speter ntfs_toupper_tab = NULL; 202518334Speter } 202618334Speter#ifdef DIAGNOSTIC 202718334Speter else if (ntfs_toupper_usecount < 0) { 202818334Speter panic("ntfs_toupper_unuse(): use count negative: %d\n", 202918334Speter ntfs_toupper_usecount); 203018334Speter } 203118334Speter#endif 203218334Speter 203318334Speter /* release the lock */ 203418334Speter lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL, NULL); 203518334Speter} 203618334Speter 203718334Speterint 203818334Speterntfs_u28_init( 203918334Speter struct ntfsmount *ntmp, 204018334Speter wchar *u2w, 204118334Speter char *cs_local, 204218334Speter char *cs_ntfs) 204318334Speter{ 204418334Speter char ** u28; 204518334Speter int i, j, h, l; 204618334Speter 204718334Speter if (ntfs_iconv && cs_local) { 204818334Speter ntfs_iconv->open(cs_local, cs_ntfs, &ntmp->ntm_ic_u2l); 204918334Speter return (0); 205018334Speter } 205118334Speter 205218334Speter MALLOC(u28, char **, 256 * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO); 205318334Speter 205418334Speter for (i=0; i<256; i++) { 205518334Speter h = (u2w[i] >> 8) & 0xFF; 205618334Speter l = (u2w[i]) &0xFF; 205718334Speter 205818334Speter if (u28[h] == NULL) { 205918334Speter MALLOC(u28[h], char *, 256 * sizeof(char), M_TEMP, M_WAITOK); 206018334Speter for (j=0; j<256; j++) 206118334Speter u28[h][j] = '_'; 206218334Speter } 206318334Speter 206418334Speter u28[h][l] = i & 0xFF; 206518334Speter } 206618334Speter 206718334Speter ntmp->ntm_u28 = u28; 206818334Speter 206918334Speter return (0); 207018334Speter} 207118334Speter 207218334Speterint 207318334Speterntfs_u28_uninit(struct ntfsmount *ntmp) 207418334Speter{ 207518334Speter char ** u28; 207618334Speter int i; 207718334Speter 207818334Speter if (ntmp->ntm_u28 == NULL) { 207918334Speter if (ntfs_iconv && ntmp->ntm_ic_u2l) { 208018334Speter ntfs_iconv->close(ntmp->ntm_ic_u2l); 208118334Speter } 208218334Speter return (0); 208318334Speter } 208418334Speter 208518334Speter u28 = ntmp->ntm_u28; 208618334Speter 208718334Speter for (i=0; i<256; i++) 208818334Speter if (u28[i] != NULL) 208918334Speter FREE(u28[i], M_TEMP); 209018334Speter 209118334Speter FREE(u28, M_TEMP); 209218334Speter 209318334Speter return (0); 209418334Speter} 209518334Speter 209618334Speterint 209718334Speterntfs_82u_init( 209818334Speter struct ntfsmount *ntmp, 209918334Speter char *cs_local, 210018334Speter char *cs_ntfs) 210118334Speter{ 210218334Speter wchar * _82u; 210318334Speter int i; 210418334Speter 210518334Speter if (ntfs_iconv && cs_local) { 210618334Speter ntfs_iconv->open(cs_ntfs, cs_local, &ntmp->ntm_ic_l2u); 210718334Speter return (0); 210818334Speter } 210918334Speter 211018334Speter MALLOC(_82u, wchar *, 256 * sizeof(wchar), M_TEMP, M_WAITOK); 211118334Speter 211218334Speter for (i=0; i<256; i++) 211318334Speter _82u[i] = i; 211418334Speter 211518334Speter ntmp->ntm_82u = _82u; 211618334Speter 211718334Speter return (0); 211818334Speter} 211918334Speter 212018334Speterint 212118334Speterntfs_82u_uninit(struct ntfsmount *ntmp) 212218334Speter{ 212318334Speter 212418334Speter if (ntmp->ntm_82u == NULL) { 212518334Speter if (ntfs_iconv && ntmp->ntm_ic_l2u) { 212618334Speter ntfs_iconv->close(ntmp->ntm_ic_l2u); 212718334Speter } 212818334Speter return (0); 212918334Speter } 213018334Speter 213118334Speter FREE(ntmp->ntm_82u, M_TEMP); 213218334Speter return (0); 213318334Speter} 213418334Speter 213518334Speter/* 213618334Speter * maps the Unicode char to 8bit equivalent 213718334Speter * XXX currently only gets lower 8bit from the Unicode char 213818334Speter * and substitutes a '_' for it if the result would be '\0'; 213950397Sobrien * something better has to be definitely though out 214018334Speter */ 214118334Speterwchar 214218334Speterntfs_u28( 214318334Speter struct ntfsmount *ntmp, 214418334Speter wchar wc) 214518334Speter{ 214618334Speter char *p, *outp, inbuf[3], outbuf[3]; 214718334Speter size_t ilen, olen; 214818334Speter 214918334Speter if (ntfs_iconv && ntmp->ntm_ic_u2l) { 215018334Speter ilen = olen = 2; 215118334Speter 215218334Speter inbuf[0] = (char)(wc>>8); 215318334Speter inbuf[1] = (char)wc; 215418334Speter inbuf[2] = '\0'; 215518334Speter p = inbuf; 215618334Speter outp = outbuf; 215718334Speter ntfs_iconv->convchr(ntmp->ntm_ic_u2l, (const char **)&p, &ilen, 215818334Speter &outp, &olen); 215918334Speter if (olen == 1) { 216018334Speter return ((wchar)(outbuf[0])); 216118334Speter } else if (olen == 0) { 216218334Speter return ((wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF))); 216318334Speter } 216418334Speter return ('?'); 216518334Speter } 216618334Speter 216718334Speter p = ntmp->ntm_u28[(wc>>8)&0xFF]; 216818334Speter if (p == NULL) 216918334Speter return ('_'); 217018334Speter return (p[wc&0xFF]); 217150397Sobrien} 217218334Speter 217318334Speterwchar 217418334Speterntfs_82u( 217518334Speter struct ntfsmount *ntmp, 217618334Speter wchar wc, 217718334Speter int *len) 217818334Speter{ 217918334Speter char *p, *outp, inbuf[3], outbuf[3]; 218018334Speter wchar uc; 218118334Speter size_t ilen, olen; 218218334Speter 218318334Speter if (ntfs_iconv && ntmp->ntm_ic_l2u) { 218418334Speter ilen = (size_t)*len; 218518334Speter olen = 2; 218618334Speter 218718334Speter inbuf[0] = (char)(wc>>8); 218818334Speter inbuf[1] = (char)wc; 218918334Speter inbuf[2] = '\0'; 219018334Speter p = inbuf; 219118334Speter outp = outbuf; 219218334Speter ntfs_iconv->convchr(ntmp->ntm_ic_l2u, (const char **)&p, &ilen, 219318334Speter &outp, &olen); 219418334Speter *len -= (int)ilen; 219518334Speter uc = (wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF)); 219618334Speter 219718334Speter return (uc); 219818334Speter } 219950397Sobrien 220018334Speter if (ntmp->ntm_82u != NULL) 220118334Speter return (ntmp->ntm_82u[wc&0xFF]); 220218334Speter 220318334Speter return ('?'); 220418334Speter} 220518334Speter 220618334Speter