ntfs_subr.c revision 93818
1193326Sed/* $NetBSD: ntfs_subr.c,v 1.23 1999/10/31 19:45:26 jdolecek Exp $ */ 2193326Sed 3193326Sed/*- 4193326Sed * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org) 5193326Sed * All rights reserved. 6193326Sed * 7193326Sed * Redistribution and use in source and binary forms, with or without 8193326Sed * modification, are permitted provided that the following conditions 9193326Sed * are met: 10193326Sed * 1. Redistributions of source code must retain the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer. 12193326Sed * 2. Redistributions in binary form must reproduce the above copyright 13193326Sed * notice, this list of conditions and the following disclaimer in the 14193326Sed * documentation and/or other materials provided with the distribution. 15193326Sed * 16193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18252723Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19245431Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20207619Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21212904Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22252723Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23226890Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24252723Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25252723Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26221345Sdim * SUCH DAMAGE. 27252723Sdim * 28193326Sed * $FreeBSD: head/sys/fs/ntfs/ntfs_subr.c 93818 2002-04-04 21:03:38Z jhb $ 29193326Sed */ 30198092Srdivacky 31235633Sdim#include <sys/param.h> 32193326Sed#include <sys/types.h> 33193326Sed#include <sys/systm.h> 34252723Sdim#include <sys/namei.h> 35193326Sed#include <sys/kernel.h> 36252723Sdim#include <sys/vnode.h> 37252723Sdim#include <sys/mount.h> 38252723Sdim#include <sys/bio.h> 39252723Sdim#include <sys/buf.h> 40245431Sdim#include <sys/file.h> 41193326Sed#include <sys/malloc.h> 42193326Sed#include <sys/lock.h> 43252723Sdim 44193326Sed/* #define NTFS_DEBUG 1 */ 45218893Sdim#include <fs/ntfs/ntfs.h> 46218893Sdim#include <fs/ntfs/ntfsmount.h> 47252723Sdim#include <fs/ntfs/ntfs_inode.h> 48252723Sdim#include <fs/ntfs/ntfs_vfsops.h> 49252723Sdim#include <fs/ntfs/ntfs_subr.h> 50193326Sed#include <fs/ntfs/ntfs_compr.h> 51207619Srdivacky#include <fs/ntfs/ntfs_ihash.h> 52226890Sdim 53207619SrdivackyMALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information"); 54245431SdimMALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data"); 55245431SdimMALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage"); 56245431SdimMALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary"); 57245431Sdim 58245431Sdimstatic int ntfs_ntlookupattr(struct ntfsmount *, const char *, int, int *, char **); 59245431Sdimstatic int ntfs_findvattr(struct ntfsmount *, struct ntnode *, struct ntvattr **, struct ntvattr **, u_int32_t, const char *, size_t, cn_t); 60245431Sdimstatic int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t); 61245431Sdimstatic int ntfs_uastrcmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t); 62245431Sdim 63245431Sdim/* table for mapping Unicode chars into uppercase; it's filled upon first 64252723Sdim * ntfs mount, freed upon last ntfs umount */ 65252723Sdimstatic wchar *ntfs_toupper_tab; 66252723Sdim#define NTFS_TOUPPER(ch) (ntfs_toupper_tab[(ch)]) 67252723Sdimstatic struct lock ntfs_toupper_lock; 68245431Sdimstatic signed int ntfs_toupper_usecount; 69252723Sdim 70252723Sdim/* support macro for ntfs_ntvattrget() */ 71252723Sdim#define NTFS_AALPCMP(aalp,type,name,namelen) ( \ 72245431Sdim (aalp->al_type == type) && (aalp->al_namelen == namelen) && \ 73245431Sdim !NTFS_UASTRCMP(aalp->al_name,aalp->al_namelen,name,namelen) ) 74252723Sdim 75252723Sdim/* 76252723Sdim * 77252723Sdim */ 78252723Sdimint 79252723Sdimntfs_ntvattrrele(vap) 80245431Sdim struct ntvattr * vap; 81245431Sdim{ 82245431Sdim dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n", 83245431Sdim vap->va_ip->i_number, vap->va_type)); 84245431Sdim 85245431Sdim ntfs_ntrele(vap->va_ip); 86245431Sdim 87245431Sdim return (0); 88245431Sdim} 89245431Sdim 90245431Sdim/* 91245431Sdim * find the attribute in the ntnode 92245431Sdim */ 93245431Sdimstatic int 94245431Sdimntfs_findvattr(ntmp, ip, lvapp, vapp, type, name, namelen, vcn) 95245431Sdim struct ntfsmount *ntmp; 96245431Sdim struct ntnode *ip; 97245431Sdim struct ntvattr **lvapp, **vapp; 98245431Sdim u_int32_t type; 99193326Sed const char *name; 100193326Sed size_t namelen; 101193326Sed cn_t vcn; 102193326Sed{ 103193326Sed int error; 104193326Sed struct ntvattr *vap; 105193326Sed 106193326Sed if((ip->i_flag & IN_LOADED) == 0) { 107218893Sdim dprintf(("ntfs_findvattr: node not loaded, ino: %d\n", 108235633Sdim ip->i_number)); 109235633Sdim error = ntfs_loadntnode(ntmp,ip); 110224145Sdim if (error) { 111218893Sdim printf("ntfs_findvattr: FAILED TO LOAD INO: %d\n", 112218893Sdim ip->i_number); 113224145Sdim return (error); 114218893Sdim } 115218893Sdim } 116218893Sdim 117193326Sed *lvapp = NULL; 118193326Sed *vapp = NULL; 119193326Sed LIST_FOREACH(vap, &ip->i_valist, va_list) { 120193326Sed ddprintf(("ntfs_findvattr: type: 0x%x, vcn: %d - %d\n", \ 121193326Sed vap->va_type, (u_int32_t) vap->va_vcnstart, \ 122193326Sed (u_int32_t) vap->va_vcnend)); 123198092Srdivacky if ((vap->va_type == type) && 124193326Sed (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) && 125198092Srdivacky (vap->va_namelen == namelen) && 126193326Sed (strncmp(name, vap->va_name, namelen) == 0)) { 127193326Sed *vapp = vap; 128193326Sed ntfs_ntref(vap->va_ip); 129193326Sed return (0); 130193326Sed } 131193326Sed if (vap->va_type == NTFS_A_ATTRLIST) 132193326Sed *lvapp = vap; 133199482Srdivacky } 134193326Sed 135193326Sed return (-1); 136198092Srdivacky} 137193326Sed 138193326Sed/* 139193326Sed * Search attribute specifed in ntnode (load ntnode if nessecary). 140193326Sed * If not found but ATTR_A_ATTRLIST present, read it in and search throught. 141193326Sed * VOP_VGET node needed, and lookup througth it's ntnode (load if nessesary). 142198092Srdivacky * 143193326Sed * ntnode should be locked 144193326Sed */ 145193326Sedint 146218893Sdimntfs_ntvattrget( 147193326Sed struct ntfsmount * ntmp, 148193326Sed struct ntnode * ip, 149235633Sdim u_int32_t type, 150235633Sdim const char *name, 151224145Sdim cn_t vcn, 152224145Sdim struct ntvattr ** vapp) 153224145Sdim{ 154193326Sed struct ntvattr *lvap = NULL; 155193326Sed struct attr_attrlist *aalp; 156193326Sed struct attr_attrlist *nextaalp; 157193326Sed struct vnode *newvp; 158193326Sed struct ntnode *newip; 159193326Sed caddr_t alpool; 160193326Sed size_t namelen, len; 161198092Srdivacky int error; 162193326Sed 163193326Sed *vapp = NULL; 164193326Sed 165193326Sed if (name) { 166218893Sdim dprintf(("ntfs_ntvattrget: " \ 167193326Sed "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 168193326Sed ip->i_number, type, name, (u_int32_t) vcn)); 169235633Sdim namelen = strlen(name); 170235633Sdim } else { 171224145Sdim dprintf(("ntfs_ntvattrget: " \ 172224145Sdim "ino: %d, type: 0x%x, vcn: %d\n", \ 173224145Sdim ip->i_number, type, (u_int32_t) vcn)); 174193326Sed name = ""; 175224145Sdim namelen = 0; 176224145Sdim } 177224145Sdim 178224145Sdim error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn); 179224145Sdim if (error >= 0) 180224145Sdim return (error); 181224145Sdim 182224145Sdim if (!lvap) { 183224145Sdim dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \ 184224145Sdim "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 185224145Sdim ip->i_number, type, name, (u_int32_t) vcn)); 186224145Sdim return (ENOENT); 187224145Sdim } 188224145Sdim /* Scan $ATTRIBUTE_LIST for requested attribute */ 189224145Sdim len = lvap->va_datalen; 190224145Sdim MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK); 191224145Sdim error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len, 192235633Sdim NULL); 193235633Sdim if (error) 194224145Sdim goto out; 195235633Sdim 196224145Sdim aalp = (struct attr_attrlist *) alpool; 197235633Sdim nextaalp = NULL; 198224145Sdim 199224145Sdim for(; len > 0; aalp = nextaalp) { 200224145Sdim dprintf(("ntfs_ntvattrget: " \ 201218893Sdim "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \ 202252723Sdim aalp->al_inumber, aalp->al_type, \ 203218893Sdim (u_int32_t) aalp->al_vcnstart)); 204218893Sdim 205218893Sdim if (len > aalp->reclen) { 206218893Sdim nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *); 207218893Sdim } else { 208218893Sdim nextaalp = NULL; 209218893Sdim } 210218893Sdim len -= aalp->reclen; 211218893Sdim 212218893Sdim if (!NTFS_AALPCMP(aalp, type, name, namelen) || 213218893Sdim (nextaalp && (nextaalp->al_vcnstart <= vcn) && 214218893Sdim NTFS_AALPCMP(nextaalp, type, name, namelen))) 215235633Sdim continue; 216235633Sdim 217218893Sdim dprintf(("ntfs_ntvattrget: attribute in ino: %d\n", 218193326Sed aalp->al_inumber)); 219218893Sdim 220218893Sdim /* this is not a main record, so we can't use just plain 221218893Sdim vget() */ 222218893Sdim error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber, 223218893Sdim NTFS_A_DATA, NULL, LK_EXCLUSIVE, 224218893Sdim VG_EXT, curthread, &newvp); 225193326Sed if (error) { 226193326Sed printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n", 227235633Sdim aalp->al_inumber); 228198092Srdivacky goto out; 229193326Sed } 230245431Sdim newip = VTONT(newvp); 231245431Sdim /* XXX have to lock ntnode */ 232245431Sdim error = ntfs_findvattr(ntmp, newip, &lvap, vapp, 233245431Sdim type, name, namelen, vcn); 234245431Sdim vput(newvp); 235245431Sdim if (error == 0) 236198092Srdivacky goto out; 237218893Sdim printf("ntfs_ntvattrget: ATTRLIST ERROR.\n"); 238218893Sdim break; 239218893Sdim } 240218893Sdim error = ENOENT; 241218893Sdim 242218893Sdim dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \ 243193326Sed "ino: %d, type: 0x%x, name: %.*s, vcn: %d\n", \ 244252723Sdim ip->i_number, type, (int) namelen, name, (u_int32_t) vcn)); 245218893Sdimout: 246218893Sdim FREE(alpool, M_TEMP); 247218893Sdim return (error); 248218893Sdim} 249218893Sdim 250218893Sdim/* 251218893Sdim * Read ntnode from disk, make ntvattr list. 252218893Sdim * 253218893Sdim * ntnode should be locked 254218893Sdim */ 255218893Sdimint 256193326Sedntfs_loadntnode( 257193326Sed struct ntfsmount * ntmp, 258193326Sed struct ntnode * ip) 259193326Sed{ 260193326Sed struct filerec *mfrp; 261221345Sdim daddr_t bn; 262201361Srdivacky int error,off; 263203955Srdivacky struct attr *ap; 264245431Sdim struct ntvattr *nvap; 265245431Sdim 266193326Sed dprintf(("ntfs_loadntnode: loading ino: %d\n",ip->i_number)); 267218893Sdim 268218893Sdim MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec), 269193326Sed M_TEMP, M_WAITOK); 270193326Sed 271193326Sed if (ip->i_number < NTFS_SYSNODESNUM) { 272193326Sed struct buf *bp; 273193326Sed 274193326Sed dprintf(("ntfs_loadntnode: read system node\n")); 275193326Sed 276193326Sed bn = ntfs_cntobn(ntmp->ntm_mftcn) + 277193326Sed ntmp->ntm_bpmftrec * ip->i_number; 278193326Sed 279193326Sed error = bread(ntmp->ntm_devvp, 280193326Sed bn, ntfs_bntob(ntmp->ntm_bpmftrec), 281201361Srdivacky NOCRED, &bp); 282203955Srdivacky if (error) { 283221345Sdim printf("ntfs_loadntnode: BREAD FAILED\n"); 284245431Sdim brelse(bp); 285245431Sdim goto out; 286193326Sed } 287245431Sdim memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec)); 288245431Sdim bqrelse(bp); 289245431Sdim } else { 290245431Sdim struct vnode *vp; 291245431Sdim 292245431Sdim vp = ntmp->ntm_sysvn[NTFS_MFTINO]; 293245431Sdim error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 294245431Sdim ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec), 295245431Sdim ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL); 296193326Sed if (error) { 297193326Sed printf("ntfs_loadntnode: ntfs_readattr failed\n"); 298198092Srdivacky goto out; 299252723Sdim } 300210299Sed } 301210299Sed 302210299Sed /* Check if magic and fixups are correct */ 303210299Sed error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp, 304210299Sed ntfs_bntob(ntmp->ntm_bpmftrec)); 305210299Sed if (error) { 306210299Sed printf("ntfs_loadntnode: BAD MFT RECORD %d\n", 307210299Sed (u_int32_t) ip->i_number); 308210299Sed goto out; 309221345Sdim } 310210299Sed 311210299Sed dprintf(("ntfs_loadntnode: load attrs for ino: %d\n",ip->i_number)); 312210299Sed off = mfrp->fr_attroff; 313245431Sdim ap = (struct attr *) ((caddr_t)mfrp + off); 314245431Sdim 315221345Sdim LIST_INIT(&ip->i_valist); 316210299Sed 317210299Sed while (ap->a_hdr.a_type != -1) { 318210299Sed error = ntfs_attrtontvattr(ntmp, &nvap, ap); 319210299Sed if (error) 320210299Sed break; 321210299Sed nvap->va_ip = ip; 322210299Sed 323210299Sed LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list); 324210299Sed 325210299Sed off += ap->a_hdr.reclen; 326210299Sed ap = (struct attr *) ((caddr_t)mfrp + off); 327210299Sed } 328210299Sed if (error) { 329210299Sed printf("ntfs_loadntnode: failed to load attr ino: %d\n", 330210299Sed ip->i_number); 331210299Sed goto out; 332210299Sed } 333210299Sed 334210299Sed ip->i_mainrec = mfrp->fr_mainrec; 335210299Sed ip->i_nlink = mfrp->fr_nlink; 336210299Sed ip->i_frflag = mfrp->fr_flags; 337210299Sed 338210299Sed ip->i_flag |= IN_LOADED; 339210299Sed 340210299Sedout: 341210299Sed FREE(mfrp, M_TEMP); 342210299Sed return (error); 343210299Sed} 344210299Sed 345210299Sed/* 346210299Sed * Routine locks ntnode and increase usecount, just opposite of 347210299Sed * ntfs_ntput(). 348210299Sed */ 349210299Sedint 350210299Sedntfs_ntget(ip) 351210299Sed struct ntnode *ip; 352210299Sed{ 353210299Sed dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n", 354210299Sed ip->i_number, ip, ip->i_usecount)); 355235633Sdim 356218893Sdim mtx_lock(&ip->i_interlock); 357218893Sdim ip->i_usecount++; 358218893Sdim lockmgr(&ip->i_lock, LK_EXCLUSIVE | LK_INTERLOCK, &ip->i_interlock, 359218893Sdim NULL); 360235633Sdim 361210299Sed return 0; 362252723Sdim} 363210299Sed 364210299Sed/* 365252723Sdim * Routine search ntnode in hash, if found: lock, inc usecount and return. 366210299Sed * If not in hash allocate structure for ntnode, prefill it, lock, 367210299Sed * inc count and return. 368210299Sed * 369210299Sed * ntnode returned locked 370210299Sed */ 371210299Sedint 372210299Sedntfs_ntlookup( 373210299Sed struct ntfsmount * ntmp, 374210299Sed ino_t ino, 375210299Sed struct ntnode ** ipp) 376210299Sed{ 377210299Sed struct ntnode *ip; 378218893Sdim 379252723Sdim dprintf(("ntfs_ntlookup: looking for ntnode %d\n", ino)); 380210299Sed 381210299Sed do { 382210299Sed if ((ip = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) { 383210299Sed ntfs_ntget(ip); 384210299Sed dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n", 385210299Sed ino, ip, ip->i_usecount)); 386210299Sed *ipp = ip; 387210299Sed return (0); 388210299Sed } 389210299Sed } while (lockmgr(&ntfs_hashlock, LK_EXCLUSIVE | LK_SLEEPFAIL, NULL, 390218893Sdim NULL)); 391218893Sdim 392218893Sdim MALLOC(ip, struct ntnode *, sizeof(struct ntnode), M_NTFSNTNODE, 393218893Sdim M_WAITOK | M_ZERO); 394218893Sdim ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip)); 395218893Sdim 396218893Sdim /* Generic initialization */ 397218893Sdim ip->i_devvp = ntmp->ntm_devvp; 398218893Sdim ip->i_dev = ntmp->ntm_dev; 399218893Sdim ip->i_number = ino; 400218893Sdim ip->i_mp = ntmp; 401218893Sdim 402218893Sdim LIST_INIT(&ip->i_fnlist); 403218893Sdim VREF(ip->i_devvp); 404218893Sdim 405218893Sdim /* init lock and lock the newborn ntnode */ 406218893Sdim lockinit(&ip->i_lock, PINOD, "ntnode", 0, LK_EXCLUSIVE); 407218893Sdim mtx_init(&ip->i_interlock, "ntnode interlock", NULL, MTX_DEF); 408218893Sdim ntfs_ntget(ip); 409218893Sdim 410218893Sdim ntfs_nthashins(ip); 411218893Sdim 412218893Sdim lockmgr(&ntfs_hashlock, LK_RELEASE, NULL, NULL); 413218893Sdim 414218893Sdim *ipp = ip; 415218893Sdim 416218893Sdim dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n", 417218893Sdim ino, ip, ip->i_usecount)); 418218893Sdim 419218893Sdim return (0); 420218893Sdim} 421218893Sdim 422218893Sdim/* 423218893Sdim * Decrement usecount of ntnode and unlock it, if usecount reach zero, 424210299Sed * deallocate ntnode. 425210299Sed * 426210299Sed * ntnode should be locked on entry, and unlocked on return. 427210299Sed */ 428210299Sedvoid 429252723Sdimntfs_ntput(ip) 430252723Sdim struct ntnode *ip; 431252723Sdim{ 432252723Sdim struct ntvattr *vap; 433252723Sdim 434252723Sdim dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n", 435252723Sdim ip->i_number, ip, ip->i_usecount)); 436193326Sed 437193326Sed mtx_lock(&ip->i_interlock); 438252723Sdim ip->i_usecount--; 439252723Sdim 440252723Sdim#ifdef DIAGNOSTIC 441252723Sdim if (ip->i_usecount < 0) { 442252723Sdim panic("ntfs_ntput: ino: %d usecount: %d \n", 443252723Sdim ip->i_number,ip->i_usecount); 444193326Sed } 445252723Sdim#endif 446252723Sdim 447193326Sed if (ip->i_usecount > 0) { 448198092Srdivacky lockmgr(&ip->i_lock, LK_RELEASE|LK_INTERLOCK, &ip->i_interlock, 449218893Sdim NULL); 450218893Sdim return; 451218893Sdim } 452218893Sdim 453245431Sdim dprintf(("ntfs_ntput: deallocating ntnode: %d\n", ip->i_number)); 454245431Sdim 455245431Sdim if (LIST_FIRST(&ip->i_fnlist)) 456203955Srdivacky panic("ntfs_ntput: ntnode has fnodes\n"); 457203955Srdivacky 458235633Sdim ntfs_nthashrem(ip); 459235633Sdim 460235633Sdim while ((vap = LIST_FIRST(&ip->i_valist)) != NULL) { 461235633Sdim LIST_REMOVE(vap,va_list); 462235633Sdim ntfs_freentvattr(vap); 463235633Sdim } 464235633Sdim mtx_unlock(&ip->i_interlock); 465235633Sdim mtx_destroy(&ip->i_interlock); 466235633Sdim lockdestroy(&ip->i_lock); 467235633Sdim vrele(ip->i_devvp); 468235633Sdim FREE(ip, M_NTFSNTNODE); 469235633Sdim} 470235633Sdim 471235633Sdim/* 472207619Srdivacky * increment usecount of ntnode 473207619Srdivacky */ 474207619Srdivackyvoid 475207619Srdivackyntfs_ntref(ip) 476207619Srdivacky struct ntnode *ip; 477235633Sdim{ 478193326Sed mtx_lock(&ip->i_interlock); 479193326Sed ip->i_usecount++; 480193326Sed mtx_unlock(&ip->i_interlock); 481193326Sed 482235633Sdim dprintf(("ntfs_ntref: ino %d, usecount: %d\n", 483235633Sdim ip->i_number, ip->i_usecount)); 484235633Sdim 485263509Sdim} 486193326Sed 487193326Sed/* 488263509Sdim * Decrement usecount of ntnode. 489263509Sdim */ 490235633Sdimvoid 491235633Sdimntfs_ntrele(ip) 492235633Sdim struct ntnode *ip; 493263509Sdim{ 494235633Sdim dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n", 495235633Sdim ip->i_number, ip, ip->i_usecount)); 496235633Sdim 497235633Sdim mtx_lock(&ip->i_interlock); 498235633Sdim ip->i_usecount--; 499235633Sdim 500263509Sdim if (ip->i_usecount < 0) 501235633Sdim panic("ntfs_ntrele: ino: %d usecount: %d \n", 502235633Sdim ip->i_number,ip->i_usecount); 503235633Sdim mtx_unlock(&ip->i_interlock); 504235633Sdim} 505235633Sdim 506235633Sdim/* 507235633Sdim * Deallocate all memory allocated for ntvattr 508252723Sdim */ 509235633Sdimvoid 510235633Sdimntfs_freentvattr(vap) 511235633Sdim struct ntvattr * vap; 512235633Sdim{ 513212904Sdim if (vap->va_flag & NTFS_AF_INRUN) { 514198092Srdivacky if (vap->va_vruncn) 515235633Sdim FREE(vap->va_vruncn, M_NTFSRUN); 516235633Sdim if (vap->va_vruncl) 517193326Sed FREE(vap->va_vruncl, M_NTFSRUN); 518193326Sed } else { 519193326Sed if (vap->va_datap) 520198092Srdivacky FREE(vap->va_datap, M_NTFSRDATA); 521235633Sdim } 522235633Sdim FREE(vap, M_NTFSNTVATTR); 523235633Sdim} 524235633Sdim 525235633Sdim/* 526235633Sdim * Convert disk image of attribute into ntvattr structure, 527235633Sdim * runs are expanded also. 528252723Sdim */ 529198092Srdivackyint 530235633Sdimntfs_attrtontvattr( 531208600Srdivacky struct ntfsmount * ntmp, 532208600Srdivacky struct ntvattr ** rvapp, 533208600Srdivacky struct attr * rap) 534208600Srdivacky{ 535208600Srdivacky int error, i; 536208600Srdivacky struct ntvattr *vap; 537193326Sed 538193326Sed error = 0; 539235633Sdim *rvapp = NULL; 540235633Sdim 541235633Sdim MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr), 542235633Sdim M_NTFSNTVATTR, M_WAITOK | M_ZERO); 543193326Sed vap->va_ip = NULL; 544235633Sdim vap->va_flag = rap->a_hdr.a_flag; 545235633Sdim vap->va_type = rap->a_hdr.a_type; 546235633Sdim vap->va_compression = rap->a_hdr.a_compression; 547235633Sdim vap->va_index = rap->a_hdr.a_index; 548235633Sdim 549235633Sdim ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index)); 550235633Sdim 551235633Sdim vap->va_namelen = rap->a_hdr.a_namelen; 552235633Sdim if (rap->a_hdr.a_namelen) { 553235633Sdim wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff); 554235633Sdim ddprintf((", name:[")); 555235633Sdim for (i = 0; i < vap->va_namelen; i++) { 556235633Sdim vap->va_name[i] = unp[i]; 557202379Srdivacky ddprintf(("%c", vap->va_name[i])); 558202379Srdivacky } 559226890Sdim ddprintf(("]")); 560226890Sdim } 561218893Sdim if (vap->va_flag & NTFS_AF_INRUN) { 562202379Srdivacky ddprintf((", nonres.")); 563235633Sdim vap->va_datalen = rap->a_nr.a_datalen; 564235633Sdim vap->va_allocated = rap->a_nr.a_allocated; 565226890Sdim vap->va_vcnstart = rap->a_nr.a_vcnstart; 566235633Sdim vap->va_vcnend = rap->a_nr.a_vcnend; 567235633Sdim vap->va_compressalg = rap->a_nr.a_compressalg; 568235633Sdim error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl), 569226890Sdim &(vap->va_vruncnt), 570235633Sdim (caddr_t) rap + rap->a_nr.a_dataoff); 571235633Sdim } else { 572218893Sdim vap->va_compressalg = 0; 573193326Sed ddprintf((", res.")); 574199482Srdivacky vap->va_datalen = rap->a_r.a_datalen; 575245431Sdim vap->va_allocated = rap->a_r.a_datalen; 576245431Sdim vap->va_vcnstart = 0; 577218893Sdim vap->va_vcnend = ntfs_btocn(vap->va_allocated); 578235633Sdim MALLOC(vap->va_datap, caddr_t, vap->va_datalen, 579235633Sdim M_NTFSRDATA, M_WAITOK); 580235633Sdim memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff, 581235633Sdim rap->a_r.a_datalen); 582263509Sdim } 583235633Sdim ddprintf((", len: %d", vap->va_datalen)); 584235633Sdim 585235633Sdim if (error) 586252723Sdim FREE(vap, M_NTFSNTVATTR); 587252723Sdim else 588193326Sed *rvapp = vap; 589263509Sdim 590263509Sdim ddprintf(("\n")); 591235633Sdim 592235633Sdim return (error); 593218893Sdim} 594193326Sed 595235633Sdim/* 596235633Sdim * Expand run into more utilizable and more memory eating format. 597235633Sdim */ 598235633Sdimint 599235633Sdimntfs_runtovrun( 600235633Sdim cn_t ** rcnp, 601252723Sdim cn_t ** rclp, 602198092Srdivacky u_long * rcntp, 603218893Sdim u_int8_t * run) 604218893Sdim{ 605218893Sdim u_int32_t off; 606218893Sdim u_int32_t sz, i; 607218893Sdim cn_t *cn; 608218893Sdim cn_t *cl; 609245431Sdim u_long cnt; 610245431Sdim cn_t prev; 611245431Sdim cn_t tmp; 612245431Sdim 613245431Sdim off = 0; 614245431Sdim cnt = 0; 615218893Sdim i = 0; 616245431Sdim while (run[off]) { 617245431Sdim off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1; 618245431Sdim cnt++; 619252723Sdim } 620252723Sdim MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK); 621218893Sdim MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK); 622218893Sdim 623218893Sdim off = 0; 624218893Sdim cnt = 0; 625218893Sdim prev = 0; 626198092Srdivacky while (run[off]) { 627198092Srdivacky 628198092Srdivacky sz = run[off++]; 629198092Srdivacky cl[cnt] = 0; 630198092Srdivacky 631235633Sdim for (i = 0; i < (sz & 0xF); i++) 632198092Srdivacky cl[cnt] += (u_int32_t) run[off++] << (i << 3); 633198092Srdivacky 634198092Srdivacky sz >>= 4; 635235633Sdim if (run[off + sz - 1] & 0x80) { 636198092Srdivacky tmp = ((u_int64_t) - 1) << (sz << 3); 637198092Srdivacky for (i = 0; i < sz; i++) 638198092Srdivacky tmp |= (u_int64_t) run[off++] << (i << 3); 639198092Srdivacky } else { 640235633Sdim tmp = 0; 641218893Sdim for (i = 0; i < sz; i++) 642218893Sdim tmp |= (u_int64_t) run[off++] << (i << 3); 643218893Sdim } 644218893Sdim if (tmp) 645218893Sdim prev = cn[cnt] = prev + tmp; 646218893Sdim else 647193326Sed cn[cnt] = tmp; 648193326Sed 649198092Srdivacky cnt++; 650193326Sed } 651198092Srdivacky *rcnp = cn; 652218893Sdim *rclp = cl; 653218893Sdim *rcntp = cnt; 654218893Sdim return (0); 655221345Sdim} 656221345Sdim 657221345Sdim/* 658221345Sdim * Compare unicode and ascii string case insens. 659221345Sdim */ 660224145Sdimstatic int 661224145Sdimntfs_uastricmp(ntmp, ustr, ustrlen, astr, astrlen) 662235633Sdim struct ntfsmount *ntmp; 663224145Sdim const wchar *ustr; 664224145Sdim size_t ustrlen; 665224145Sdim const char *astr; 666235633Sdim size_t astrlen; 667235633Sdim{ 668235633Sdim size_t i; 669224145Sdim int res; 670245431Sdim 671245431Sdim /* 672245431Sdim * XXX We use NTFS_82U(NTFS_U28(c)) to get rid of unicode 673245431Sdim * symbols not covered by translation table 674193326Sed */ 675198092Srdivacky for (i = 0; i < ustrlen && i < astrlen; i++) { 676193326Sed res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i])))) - 677193326Sed ((int)NTFS_TOUPPER(NTFS_82U(astr[i]))); 678235633Sdim if (res) 679193326Sed return res; 680193326Sed } 681193326Sed return (ustrlen - astrlen); 682235633Sdim} 683198092Srdivacky 684235633Sdim/* 685235633Sdim * Compare unicode and ascii string case sens. 686235633Sdim */ 687208600Srdivackystatic int 688223017Sdimntfs_uastrcmp(ntmp, ustr, ustrlen, astr, astrlen) 689223017Sdim struct ntfsmount *ntmp; 690235633Sdim const wchar *ustr; 691223017Sdim size_t ustrlen; 692235633Sdim const char *astr; 693223017Sdim size_t astrlen; 694223017Sdim{ 695223017Sdim size_t i; 696235633Sdim int res; 697218893Sdim 698218893Sdim for (i = 0; (i < ustrlen) && (i < astrlen); i++) { 699235633Sdim res = (int) (((char)NTFS_U28(ustr[i])) - astr[i]); 700218893Sdim if (res) 701218893Sdim return res; 702235633Sdim } 703235633Sdim return (ustrlen - astrlen); 704235633Sdim} 705218893Sdim 706218893Sdim/* 707218893Sdim * Search fnode in ntnode, if not found allocate and preinitialize. 708193326Sed * 709193326Sed * ntnode should be locked on entry. 710193326Sed */ 711235633Sdimint 712198092Srdivackyntfs_fget( 713245431Sdim struct ntfsmount *ntmp, 714245431Sdim struct ntnode *ip, 715245431Sdim int attrtype, 716245431Sdim char *attrname, 717245431Sdim struct fnode **fpp) 718245431Sdim{ 719245431Sdim struct fnode *fp; 720200583Srdivacky 721200583Srdivacky dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n", 722200583Srdivacky ip->i_number,attrtype, attrname?attrname:"")); 723235633Sdim *fpp = NULL; 724200583Srdivacky LIST_FOREACH(fp, &ip->i_fnlist, f_fnlist){ 725200583Srdivacky dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n", 726200583Srdivacky fp->f_attrtype, fp->f_attrname?fp->f_attrname:"")); 727200583Srdivacky 728235633Sdim if ((attrtype == fp->f_attrtype) && 729218893Sdim ((!attrname && !fp->f_attrname) || 730218893Sdim (attrname && fp->f_attrname && 731218893Sdim !strcmp(attrname,fp->f_attrname)))){ 732206125Srdivacky dprintf(("ntfs_fget: found existed: %p\n",fp)); 733221345Sdim *fpp = fp; 734221345Sdim } 735224145Sdim } 736235633Sdim 737224145Sdim if (*fpp) 738224145Sdim return (0); 739235633Sdim 740193326Sed MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, 741193326Sed M_WAITOK | M_ZERO); 742235633Sdim dprintf(("ntfs_fget: allocating fnode: %p\n",fp)); 743193326Sed 744193326Sed fp->f_ip = ip; 745235633Sdim if (attrname) { 746193326Sed fp->f_flag |= FN_AATTRNAME; 747193326Sed MALLOC(fp->f_attrname, char *, strlen(attrname)+1, M_TEMP, M_WAITOK); 748198092Srdivacky strcpy(fp->f_attrname, attrname); 749252723Sdim } else 750193326Sed fp->f_attrname = NULL; 751245431Sdim fp->f_attrtype = attrtype; 752245431Sdim 753245431Sdim ntfs_ntref(ip); 754245431Sdim 755245431Sdim LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist); 756245431Sdim 757245431Sdim *fpp = fp; 758245431Sdim 759245431Sdim return (0); 760245431Sdim} 761245431Sdim 762263509Sdim/* 763263509Sdim * Deallocate fnode, remove it from ntnode's fnode list. 764263509Sdim * 765263509Sdim * ntnode should be locked. 766245431Sdim */ 767245431Sdimvoid 768245431Sdimntfs_frele( 769245431Sdim struct fnode *fp) 770245431Sdim{ 771245431Sdim struct ntnode *ip = FTONT(fp); 772198092Srdivacky 773193326Sed dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip)); 774198092Srdivacky 775193326Sed dprintf(("ntfs_frele: deallocating fnode\n")); 776193326Sed LIST_REMOVE(fp,f_fnlist); 777193326Sed if (fp->f_flag & FN_AATTRNAME) 778198092Srdivacky FREE(fp->f_attrname, M_TEMP); 779193326Sed if (fp->f_dirblbuf) 780193326Sed FREE(fp->f_dirblbuf, M_NTFSDIR); 781193326Sed lockdestroy(&fp->f_lock); 782193326Sed FREE(fp, M_NTFSFNODE); 783218893Sdim ntfs_ntrele(ip); 784218893Sdim} 785218893Sdim 786218893Sdim/* 787218893Sdim * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME], 788218893Sdim * $ATTR_TYPE is searched in attrdefs read from $AttrDefs. 789218893Sdim * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed. 790218893Sdim */ 791218893Sdimstatic int 792235633Sdimntfs_ntlookupattr( 793218893Sdim struct ntfsmount * ntmp, 794235633Sdim const char * name, 795235633Sdim int namelen, 796235633Sdim int *attrtype, 797218893Sdim char **attrname) 798235633Sdim{ 799235633Sdim const char *sys; 800235633Sdim size_t syslen, i; 801224145Sdim struct ntvattrdef *adp; 802235633Sdim 803235633Sdim if (namelen == 0) 804218893Sdim return (0); 805218893Sdim 806218893Sdim if (name[0] == '$') { 807218893Sdim sys = name; 808218893Sdim for (syslen = 0; syslen < namelen; syslen++) { 809218893Sdim if(sys[syslen] == ':') { 810218893Sdim name++; 811218893Sdim namelen--; 812218893Sdim break; 813218893Sdim } 814218893Sdim } 815218893Sdim name += syslen; 816235633Sdim namelen -= syslen; 817252723Sdim 818252723Sdim adp = ntmp->ntm_ad; 819218893Sdim for (i = 0; i < ntmp->ntm_adnum; i++, adp++){ 820252723Sdim if (syslen != adp->ad_namelen || 821252723Sdim strncmp(sys, adp->ad_name, syslen) != 0) 822252723Sdim continue; 823235633Sdim 824218893Sdim *attrtype = adp->ad_type; 825218893Sdim goto out; 826218893Sdim } 827218893Sdim return (ENOENT); 828218893Sdim } else 829218893Sdim *attrtype = NTFS_A_DATA; 830218893Sdim 831218893Sdim out: 832218893Sdim if (namelen) { 833218893Sdim MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK); 834218893Sdim memcpy((*attrname), name, namelen); 835218893Sdim (*attrname)[namelen] = '\0'; 836218893Sdim } 837218893Sdim 838218893Sdim return (0); 839218893Sdim} 840218893Sdim 841218893Sdim/* 842218893Sdim * Lookup specifed node for filename, matching cnp, 843218893Sdim * return fnode filled. 844218893Sdim */ 845221345Sdimint 846221345Sdimntfs_ntlookupfile( 847221345Sdim struct ntfsmount * ntmp, 848221345Sdim struct vnode * vp, 849221345Sdim struct componentname * cnp, 850221345Sdim struct vnode ** vpp) 851221345Sdim{ 852221345Sdim struct fnode *fp = VTOF(vp); 853221345Sdim struct ntnode *ip = FTONT(fp); 854221345Sdim struct ntvattr *vap; /* Root attribute */ 855221345Sdim cn_t cn; /* VCN in current attribute */ 856221345Sdim caddr_t rdbuf; /* Buffer to read directory's blocks */ 857221345Sdim u_int32_t blsize; 858221345Sdim u_int32_t rdsize; /* Length of data to read from current block */ 859221345Sdim struct attr_indexentry *iep; 860221345Sdim int error, res, anamelen, fnamelen; 861221345Sdim const char *fname,*aname; 862235633Sdim u_int32_t aoff; 863221345Sdim int attrtype = NTFS_A_DATA; 864235633Sdim char *attrname = NULL; 865235633Sdim struct fnode *nfp; 866235633Sdim struct vnode *nvp; 867235633Sdim enum vtype f_type; 868193326Sed 869221345Sdim error = ntfs_ntget(ip); 870221345Sdim if (error) 871212904Sdim return (error); 872221345Sdim 873193326Sed error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 874193326Sed if (error || (vap->va_flag & NTFS_AF_INRUN)) 875221345Sdim return (ENOTDIR); 876221345Sdim 877212904Sdim blsize = vap->va_a_iroot->ir_size; 878212904Sdim rdsize = vap->va_datalen; 879221345Sdim 880221345Sdim /* 881221345Sdim * Divide file name into: foofilefoofilefoofile[:attrspec] 882221345Sdim * Store like this: fname:fnamelen [aname:anamelen] 883198893Srdivacky */ 884221345Sdim fname = cnp->cn_nameptr; 885221345Sdim aname = NULL; 886221345Sdim anamelen = 0; 887221345Sdim for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++) 888198893Srdivacky if(fname[fnamelen] == ':') { 889212904Sdim aname = fname + fnamelen + 1; 890221345Sdim anamelen = cnp->cn_namelen - fnamelen - 1; 891221345Sdim dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n", 892221345Sdim fname, fnamelen, aname, anamelen)); 893210299Sed break; 894221345Sdim } 895263509Sdim 896221345Sdim dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %d\n", blsize, rdsize)); 897221345Sdim 898221345Sdim MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK); 899221345Sdim 900221345Sdim error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30", 901221345Sdim 0, rdsize, rdbuf, NULL); 902221345Sdim if (error) 903221345Sdim goto fail; 904263509Sdim 905221345Sdim aoff = sizeof(struct attr_indexroot); 906221345Sdim 907221345Sdim do { 908221345Sdim iep = (struct attr_indexentry *) (rdbuf + aoff); 909263509Sdim 910235633Sdim for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 911235633Sdim aoff += iep->reclen, 912235633Sdim iep = (struct attr_indexentry *) (rdbuf + aoff)) 913235633Sdim { 914221345Sdim ddprintf(("scan: %d, %d\n", 915212904Sdim (u_int32_t) iep->ie_number, 916218893Sdim (u_int32_t) iep->ie_fnametype)); 917212904Sdim 918210299Sed /* check the name - the case-insensitible check 919210299Sed * has to come first, to break from this for loop 920210299Sed * if needed, so we can dive correctly */ 921221345Sdim res = NTFS_UASTRICMP(iep->ie_fname, iep->ie_fnamelen, 922199990Srdivacky fname, fnamelen); 923199990Srdivacky if (res > 0) break; 924263509Sdim if (res < 0) continue; 925199990Srdivacky 926193326Sed if (iep->ie_fnametype == 0 || 927235633Sdim !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS)) 928235633Sdim { 929224145Sdim res = NTFS_UASTRCMP(iep->ie_fname, 930224145Sdim iep->ie_fnamelen, fname, fnamelen); 931224145Sdim if (res != 0) continue; 932221345Sdim } 933235633Sdim 934221345Sdim if (aname) { 935226890Sdim error = ntfs_ntlookupattr(ntmp, 936235633Sdim aname, anamelen, 937235633Sdim &attrtype, &attrname); 938199990Srdivacky if (error) 939193326Sed goto fail; 940263509Sdim } 941221345Sdim 942235633Sdim /* Check if we've found ourself */ 943200583Srdivacky if ((iep->ie_number == ip->i_number) && 944235633Sdim (attrtype == fp->f_attrtype) && 945198893Srdivacky ((!attrname && !fp->f_attrname) || 946218893Sdim (attrname && fp->f_attrname && 947221345Sdim !strcmp(attrname, fp->f_attrname)))) 948199990Srdivacky { 949210299Sed VREF(vp); 950263509Sdim *vpp = vp; 951221345Sdim error = 0; 952235633Sdim goto fail; 953212904Sdim } 954235633Sdim 955212904Sdim /* vget node, but don't load it */ 956218893Sdim error = ntfs_vgetex(ntmp->ntm_mountp, 957221345Sdim iep->ie_number, attrtype, attrname, 958212904Sdim LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN, 959212904Sdim curthread, &nvp); 960210299Sed 961263509Sdim /* free the buffer returned by ntfs_ntlookupattr() */ 962221345Sdim if (attrname) { 963221345Sdim FREE(attrname, M_TEMP); 964235633Sdim attrname = NULL; 965218893Sdim } 966193326Sed 967221345Sdim if (error) 968221345Sdim goto fail; 969221345Sdim 970221345Sdim nfp = VTOF(nvp); 971212904Sdim 972212904Sdim if (nfp->f_flag & FN_VALID) { 973212904Sdim *vpp = nvp; 974212904Sdim goto fail; 975193326Sed } 976193326Sed 977235633Sdim nfp->f_fflag = iep->ie_fflag; 978235633Sdim nfp->f_pnumber = iep->ie_fpnumber; 979198092Srdivacky nfp->f_times = iep->ie_ftimes; 980198893Srdivacky 981198893Srdivacky if((nfp->f_fflag & NTFS_FFLAG_DIR) && 982221345Sdim (nfp->f_attrtype == NTFS_A_DATA) && 983221345Sdim (nfp->f_attrname == NULL)) 984221345Sdim f_type = VDIR; 985198893Srdivacky else 986198893Srdivacky f_type = VREG; 987198893Srdivacky 988198893Srdivacky nvp->v_type = f_type; 989221345Sdim 990221345Sdim if ((nfp->f_attrtype == NTFS_A_DATA) && 991198893Srdivacky (nfp->f_attrname == NULL)) 992221345Sdim { 993221345Sdim /* Opening default attribute */ 994221345Sdim nfp->f_size = iep->ie_fsize; 995221345Sdim nfp->f_allocated = iep->ie_fallocated; 996221345Sdim nfp->f_flag |= FN_PRELOADED; 997221345Sdim } else { 998221345Sdim error = ntfs_filesize(ntmp, nfp, 999221345Sdim &nfp->f_size, &nfp->f_allocated); 1000221345Sdim if (error) { 1001221345Sdim vput(nvp); 1002263509Sdim goto fail; 1003221345Sdim } 1004221345Sdim } 1005221345Sdim 1006221345Sdim nfp->f_flag &= ~FN_VALID; 1007221345Sdim *vpp = nvp; 1008221345Sdim goto fail; 1009221345Sdim } 1010221345Sdim 1011221345Sdim /* Dive if possible */ 1012221345Sdim if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) { 1013221345Sdim dprintf(("ntfs_ntlookupfile: diving\n")); 1014221345Sdim 1015221345Sdim cn = *(cn_t *) (rdbuf + aoff + 1016221345Sdim iep->reclen - sizeof(cn_t)); 1017235633Sdim rdsize = blsize; 1018235633Sdim 1019198893Srdivacky error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30", 1020221345Sdim ntfs_cntob(cn), rdsize, rdbuf, NULL); 1021235633Sdim if (error) 1022235633Sdim goto fail; 1023235633Sdim 1024235633Sdim error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1025235633Sdim rdbuf, rdsize); 1026221345Sdim if (error) 1027235633Sdim goto fail; 1028221345Sdim 1029199990Srdivacky aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize + 1030221345Sdim 0x18); 1031235633Sdim } else { 1032221345Sdim dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n")); 1033221345Sdim error = ENOENT; 1034235633Sdim break; 1035212904Sdim } 1036221345Sdim } while (1); 1037235633Sdim 1038235633Sdim dprintf(("finish\n")); 1039235633Sdim 1040235633Sdimfail: 1041235633Sdim if (attrname) FREE(attrname, M_TEMP); 1042235633Sdim ntfs_ntvattrrele(vap); 1043235633Sdim ntfs_ntput(ip); 1044235633Sdim FREE(rdbuf, M_TEMP); 1045235633Sdim return (error); 1046235633Sdim} 1047235633Sdim 1048235633Sdim/* 1049235633Sdim * Check if name type is permitted to show. 1050235633Sdim */ 1051235633Sdimint 1052235633Sdimntfs_isnamepermitted( 1053235633Sdim struct ntfsmount * ntmp, 1054235633Sdim struct attr_indexentry * iep) 1055235633Sdim{ 1056235633Sdim if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) 1057235633Sdim return 1; 1058235633Sdim 1059235633Sdim switch (iep->ie_fnametype) { 1060235633Sdim case 2: 1061235633Sdim ddprintf(("ntfs_isnamepermitted: skiped DOS name\n")); 1062235633Sdim return 0; 1063235633Sdim case 0: case 1: case 3: 1064235633Sdim return 1; 1065235633Sdim default: 1066235633Sdim printf("ntfs_isnamepermitted: " \ 1067235633Sdim "WARNING! Unknown file name type: %d\n", 1068235633Sdim iep->ie_fnametype); 1069235633Sdim break; 1070235633Sdim } 1071212904Sdim return 0; 1072212904Sdim} 1073235633Sdim 1074235633Sdim/* 1075235633Sdim * Read ntfs dir like stream of attr_indexentry, not like btree of them. 1076235633Sdim * This is done by scaning $BITMAP:$I30 for busy clusters and reading them. 1077235633Sdim * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in 1078235633Sdim * fnode, so we can skip toward record number num almost immediatly. 1079235633Sdim * Anyway this is rather slow routine. The problem is that we don't know 1080226890Sdim * how many records are there in $INDEX_ALLOCATION:$I30 block. 1081212904Sdim */ 1082212904Sdimint 1083212904Sdimntfs_ntreaddir( 1084212904Sdim struct ntfsmount * ntmp, 1085212904Sdim struct fnode * fp, 1086212904Sdim u_int32_t num, 1087235633Sdim struct attr_indexentry ** riepp) 1088212904Sdim{ 1089212904Sdim struct ntnode *ip = FTONT(fp); 1090212904Sdim struct ntvattr *vap = NULL; /* IndexRoot attribute */ 1091221345Sdim struct ntvattr *bmvap = NULL; /* BitMap attribute */ 1092199990Srdivacky struct ntvattr *iavap = NULL; /* IndexAllocation attribute */ 1093199990Srdivacky caddr_t rdbuf; /* Buffer to read directory's blocks */ 1094199990Srdivacky u_char *bmp = NULL; /* Bitmap */ 1095212904Sdim u_int32_t blsize; /* Index allocation size (2048) */ 1096212904Sdim u_int32_t rdsize; /* Length of data to read */ 1097199990Srdivacky u_int32_t attrnum; /* Current attribute type */ 1098221345Sdim u_int32_t cpbl = 1; /* Clusters per directory block */ 1099198893Srdivacky u_int32_t blnum; 1100198893Srdivacky struct attr_indexentry *iep; 1101198893Srdivacky int error = ENOENT; 1102212904Sdim u_int32_t aoff, cnum; 1103198893Srdivacky 1104221345Sdim dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num)); 1105212904Sdim error = ntfs_ntget(ip); 1106198893Srdivacky if (error) 1107221345Sdim return (error); 1108198893Srdivacky 1109198893Srdivacky error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 1110198893Srdivacky if (error) 1111212904Sdim return (ENOTDIR); 1112198893Srdivacky 1113221345Sdim if (fp->f_dirblbuf == NULL) { 1114212904Sdim fp->f_dirblsz = vap->va_a_iroot->ir_size; 1115198893Srdivacky MALLOC(fp->f_dirblbuf, caddr_t, 1116221345Sdim max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK); 1117226890Sdim } 1118226890Sdim 1119226890Sdim blsize = fp->f_dirblsz; 1120226890Sdim rdbuf = fp->f_dirblbuf; 1121226890Sdim 1122226890Sdim dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize)); 1123226890Sdim 1124226890Sdim if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) { 1125226890Sdim error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 1126226890Sdim 0, &bmvap); 1127226890Sdim if (error) { 1128226890Sdim error = ENOTDIR; 1129235633Sdim goto fail; 1130235633Sdim } 1131235633Sdim MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK); 1132235633Sdim error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0, 1133235633Sdim bmvap->va_datalen, bmp, NULL); 1134235633Sdim if (error) 1135198092Srdivacky goto fail; 1136199990Srdivacky 1137193326Sed error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30", 1138198092Srdivacky 0, &iavap); 1139193326Sed if (error) { 1140218893Sdim error = ENOTDIR; 1141221345Sdim goto fail; 1142212904Sdim } 1143212904Sdim cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1); 1144193326Sed dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n", 1145193326Sed iavap->va_datalen, cpbl)); 1146193326Sed } else { 1147193326Sed dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n")); 1148193326Sed iavap = bmvap = NULL; 1149193326Sed bmp = NULL; 1150193326Sed } 1151193326Sed 1152245431Sdim /* Try use previous values */ 1153263509Sdim if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) { 1154203955Srdivacky attrnum = fp->f_lastdattr; 1155203955Srdivacky aoff = fp->f_lastdoff; 1156203955Srdivacky blnum = fp->f_lastdblnum; 1157203955Srdivacky cnum = fp->f_lastdnum; 1158193326Sed } else { 1159198092Srdivacky attrnum = NTFS_A_INDXROOT; 1160193326Sed aoff = sizeof(struct attr_indexroot); 1161193326Sed blnum = 0; 1162193326Sed cnum = 0; 1163193326Sed } 1164198092Srdivacky 1165218893Sdim do { 1166235633Sdim dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n", 1167224145Sdim attrnum, (u_int32_t) blnum, cnum, num, aoff)); 1168218893Sdim rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize; 1169218893Sdim error = ntfs_readattr(ntmp, ip, attrnum, "$I30", 1170198092Srdivacky ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL); 1171193326Sed if (error) 1172198092Srdivacky goto fail; 1173193326Sed 1174193326Sed if (attrnum == NTFS_A_INDX) { 1175193326Sed error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1176193326Sed rdbuf, rdsize); 1177193326Sed if (error) 1178193326Sed goto fail; 1179193326Sed } 1180193326Sed if (aoff == 0) 1181203955Srdivacky aoff = (attrnum == NTFS_A_INDX) ? 1182198092Srdivacky (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) : 1183252723Sdim sizeof(struct attr_indexroot); 1184252723Sdim 1185193326Sed iep = (struct attr_indexentry *) (rdbuf + aoff); 1186198092Srdivacky for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 1187198092Srdivacky aoff += iep->reclen, 1188193326Sed iep = (struct attr_indexentry *) (rdbuf + aoff)) 1189198092Srdivacky { 1190193326Sed if (!ntfs_isnamepermitted(ntmp, iep)) continue; 1191218893Sdim 1192193326Sed if (cnum >= num) { 1193193326Sed fp->f_lastdnum = cnum; 1194212904Sdim fp->f_lastdoff = aoff; 1195212904Sdim fp->f_lastdblnum = blnum; 1196212904Sdim fp->f_lastdattr = attrnum; 1197212904Sdim 1198212904Sdim *riepp = iep; 1199212904Sdim 1200212904Sdim error = 0; 1201212904Sdim goto fail; 1202212904Sdim } 1203212904Sdim cnum++; 1204212904Sdim } 1205212904Sdim 1206212904Sdim if (iavap) { 1207235633Sdim if (attrnum == NTFS_A_INDXROOT) 1208212904Sdim blnum = 0; 1209212904Sdim else 1210212904Sdim blnum++; 1211245431Sdim 1212245431Sdim while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) { 1213212904Sdim if (bmp[blnum >> 3] & (1 << (blnum & 3))) 1214212904Sdim break; 1215235633Sdim blnum++; 1216212904Sdim } 1217212904Sdim 1218212904Sdim attrnum = NTFS_A_INDX; 1219212904Sdim aoff = 0; 1220212904Sdim if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen) 1221212904Sdim break; 1222212904Sdim dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum)); 1223212904Sdim } 1224263509Sdim } while (iavap); 1225212904Sdim 1226212904Sdim *riepp = NULL; 1227235633Sdim fp->f_lastdnum = 0; 1228235633Sdim 1229235633Sdimfail: 1230263509Sdim if (vap) 1231263509Sdim ntfs_ntvattrrele(vap); 1232263509Sdim if (bmvap) 1233212904Sdim ntfs_ntvattrrele(bmvap); 1234212904Sdim if (iavap) 1235235633Sdim ntfs_ntvattrrele(iavap); 1236235633Sdim if (bmp) 1237252723Sdim FREE(bmp, M_TEMP); 1238252723Sdim ntfs_ntput(ip); 1239235633Sdim return (error); 1240263509Sdim} 1241212904Sdim 1242212904Sdim/* 1243212904Sdim * Convert NTFS times that are in 100 ns units and begins from 1244212904Sdim * 1601 Jan 1 into unix times. 1245235633Sdim */ 1246193326Sedstruct timespec 1247212904Sdimntfs_nttimetounix( 1248212904Sdim u_int64_t nt) 1249212904Sdim{ 1250212904Sdim struct timespec t; 1251212904Sdim 1252193326Sed /* WindowNT times are in 100 ns and from 1601 Jan 1 */ 1253198092Srdivacky t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100; 1254193326Sed t.tv_sec = nt / (1000 * 1000 * 10) - 1255263509Sdim 369LL * 365LL * 24LL * 60LL * 60LL - 1256245431Sdim 89LL * 1LL * 24LL * 60LL * 60LL; 1257193326Sed return (t); 1258223017Sdim} 1259223017Sdim 1260223017Sdim/* 1261223017Sdim * Get file times from NTFS_A_NAME attribute. 1262263509Sdim */ 1263212904Sdimint 1264223017Sdimntfs_times( 1265263509Sdim struct ntfsmount * ntmp, 1266193326Sed struct ntnode * ip, 1267252723Sdim ntfs_times_t * tm) 1268252723Sdim{ 1269193326Sed struct ntvattr *vap; 1270193326Sed int error; 1271193326Sed 1272193326Sed dprintf(("ntfs_times: ino: %d...\n", ip->i_number)); 1273193326Sed 1274193326Sed error = ntfs_ntget(ip); 1275198092Srdivacky if (error) 1276198092Srdivacky return (error); 1277193326Sed 1278198092Srdivacky error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap); 1279193326Sed if (error) { 1280218893Sdim ntfs_ntput(ip); 1281193326Sed return (error); 1282193326Sed } 1283193326Sed *tm = vap->va_a_name->n_times; 1284226890Sdim ntfs_ntvattrrele(vap); 1285226890Sdim ntfs_ntput(ip); 1286226890Sdim 1287226890Sdim return (0); 1288226890Sdim} 1289226890Sdim 1290226890Sdim/* 1291226890Sdim * Get file sizes from corresponding attribute. 1292226890Sdim * 1293193326Sed * ntnode under fnode should be locked. 1294193326Sed */ 1295193326Sedint 1296193326Sedntfs_filesize( 1297226890Sdim struct ntfsmount * ntmp, 1298226890Sdim struct fnode * fp, 1299218893Sdim u_int64_t * size, 1300224145Sdim u_int64_t * bytes) 1301235633Sdim{ 1302235633Sdim struct ntvattr *vap; 1303193326Sed struct ntnode *ip = FTONT(fp); 1304193326Sed u_int64_t sz, bn; 1305193326Sed int error; 1306193326Sed 1307193326Sed dprintf(("ntfs_filesize: ino: %d\n", ip->i_number)); 1308198092Srdivacky 1309235633Sdim error = ntfs_ntvattrget(ntmp, ip, 1310235633Sdim fp->f_attrtype, fp->f_attrname, 0, &vap); 1311235633Sdim if (error) 1312193326Sed return (error); 1313252723Sdim 1314252723Sdim bn = vap->va_allocated; 1315198092Srdivacky sz = vap->va_datalen; 1316193326Sed 1317193326Sed dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n", 1318193326Sed (u_int32_t) sz, (u_int32_t) bn)); 1319235633Sdim 1320193326Sed if (size) 1321193326Sed *size = sz; 1322198092Srdivacky if (bytes) 1323198092Srdivacky *bytes = bn; 1324193326Sed 1325193326Sed ntfs_ntvattrrele(vap); 1326193326Sed 1327218893Sdim return (0); 1328193326Sed} 1329193326Sed 1330235633Sdim/* 1331193326Sed * This is one of write routine. 1332212904Sdim */ 1333263509Sdimint 1334245431Sdimntfs_writeattr_plain( 1335193326Sed struct ntfsmount * ntmp, 1336193326Sed struct ntnode * ip, 1337263509Sdim u_int32_t attrnum, 1338193326Sed char *attrname, 1339212904Sdim off_t roff, 1340263509Sdim size_t rsize, 1341212904Sdim void *rdata, 1342263509Sdim size_t * initp, 1343193326Sed struct uio *uio) 1344235633Sdim{ 1345252723Sdim size_t init; 1346235633Sdim int error = 0; 1347263509Sdim off_t off = roff, left = rsize, towrite; 1348252723Sdim caddr_t data = rdata; 1349235633Sdim struct ntvattr *vap; 1350212904Sdim *initp = 0; 1351212904Sdim 1352252723Sdim while (left) { 1353252723Sdim error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1354252723Sdim ntfs_btocn(off), &vap); 1355252723Sdim if (error) 1356252723Sdim return (error); 1357252723Sdim towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1358252723Sdim ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n", 1359252723Sdim (u_int32_t) off, (u_int32_t) towrite, 1360252723Sdim (u_int32_t) vap->va_vcnstart, 1361252723Sdim (u_int32_t) vap->va_vcnend)); 1362252723Sdim error = ntfs_writentvattr_plain(ntmp, ip, vap, 1363252723Sdim off - ntfs_cntob(vap->va_vcnstart), 1364252723Sdim towrite, data, &init, uio); 1365252723Sdim if (error) { 1366252723Sdim printf("ntfs_writeattr_plain: " \ 1367252723Sdim "ntfs_writentvattr_plain failed: o: %d, s: %d\n", 1368252723Sdim (u_int32_t) off, (u_int32_t) towrite); 1369252723Sdim printf("ntfs_writeattr_plain: attrib: %d - %d\n", 1370235633Sdim (u_int32_t) vap->va_vcnstart, 1371235633Sdim (u_int32_t) vap->va_vcnend); 1372193326Sed ntfs_ntvattrrele(vap); 1373193326Sed break; 1374193326Sed } 1375193326Sed ntfs_ntvattrrele(vap); 1376193326Sed left -= towrite; 1377198092Srdivacky off += towrite; 1378193326Sed data = data + towrite; 1379193326Sed *initp += init; 1380193326Sed } 1381252723Sdim 1382252723Sdim return (error); 1383193326Sed} 1384198092Srdivacky 1385198092Srdivacky/* 1386193326Sed * This is one of write routine. 1387198092Srdivacky * 1388193326Sed * ntnode should be locked. 1389218893Sdim */ 1390193326Sedint 1391193326Sedntfs_writentvattr_plain( 1392193326Sed struct ntfsmount * ntmp, 1393193326Sed struct ntnode * ip, 1394193326Sed struct ntvattr * vap, 1395193326Sed off_t roff, 1396193326Sed size_t rsize, 1397193326Sed void *rdata, 1398193326Sed size_t * initp, 1399193326Sed struct uio *uio) 1400193326Sed{ 1401218893Sdim int error = 0; 1402224145Sdim int off; 1403218893Sdim int cnt; 1404198092Srdivacky cn_t ccn, ccl, cn, left, cl; 1405193326Sed caddr_t data = rdata; 1406198092Srdivacky struct buf *bp; 1407193326Sed size_t tocopy; 1408193326Sed 1409193326Sed *initp = 0; 1410193326Sed 1411193326Sed if ((vap->va_flag & NTFS_AF_INRUN) == 0) { 1412193326Sed printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n"); 1413252723Sdim return ENOTTY; 1414252723Sdim } 1415252723Sdim 1416198092Srdivacky ddprintf(("ntfs_writentvattr_plain: data in run: %ld chains\n", 1417198092Srdivacky vap->va_vruncnt)); 1418193326Sed 1419198092Srdivacky off = roff; 1420193326Sed left = rsize; 1421218893Sdim ccl = 0; 1422193326Sed ccn = 0; 1423193326Sed cnt = 0; 1424193326Sed for (; left && (cnt < vap->va_vruncnt); cnt++) { 1425263509Sdim ccn = vap->va_vruncn[cnt]; 1426193326Sed ccl = vap->va_vruncl[cnt]; 1427193326Sed 1428193326Sed ddprintf(("ntfs_writentvattr_plain: " \ 1429193326Sed "left %d, cn: 0x%x, cl: %d, off: %d\n", \ 1430193326Sed (u_int32_t) left, (u_int32_t) ccn, \ 1431193326Sed (u_int32_t) ccl, (u_int32_t) off)); 1432193326Sed 1433193326Sed if (ntfs_cntob(ccl) < off) { 1434193326Sed off -= ntfs_cntob(ccl); 1435193326Sed cnt++; 1436193326Sed continue; 1437193326Sed } 1438193326Sed if (!ccn && ip->i_number != NTFS_BOOTINO) 1439193326Sed continue; /* XXX */ 1440193326Sed 1441226890Sdim ccl -= ntfs_btocn(off); 1442226890Sdim cn = ccn + ntfs_btocn(off); 1443226890Sdim off = ntfs_btocnoff(off); 1444226890Sdim 1445226890Sdim while (left && ccl) { 1446226890Sdim tocopy = min(left, 1447226890Sdim min(ntfs_cntob(ccl) - off, MAXBSIZE - off)); 1448226890Sdim cl = ntfs_btocl(tocopy + off); 1449226890Sdim ddprintf(("ntfs_writentvattr_plain: write: " \ 1450226890Sdim "cn: 0x%x cl: %d, off: %d len: %d, left: %d\n", 1451221345Sdim (u_int32_t) cn, (u_int32_t) cl, 1452221345Sdim (u_int32_t) off, (u_int32_t) tocopy, 1453235633Sdim (u_int32_t) left)); 1454235633Sdim if ((off == 0) && (tocopy == ntfs_cntob(cl))) 1455235633Sdim { 1456235633Sdim bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn), 1457235633Sdim ntfs_cntob(cl), 0, 0); 1458235633Sdim clrbuf(bp); 1459235633Sdim } else { 1460235633Sdim error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn), 1461235633Sdim ntfs_cntob(cl), NOCRED, &bp); 1462193326Sed if (error) { 1463193326Sed brelse(bp); 1464193326Sed return (error); 1465218893Sdim } 1466224145Sdim } 1467224145Sdim if (uio) 1468198092Srdivacky uiomove(bp->b_data + off, tocopy, uio); 1469235633Sdim else 1470235633Sdim memcpy(bp->b_data + off, data, tocopy); 1471193326Sed bawrite(bp); 1472193326Sed data = data + tocopy; 1473193326Sed *initp += tocopy; 1474263509Sdim off = 0; 1475263509Sdim left -= tocopy; 1476193326Sed cn += cl; 1477193326Sed ccl -= cl; 1478193326Sed } 1479263509Sdim } 1480263509Sdim 1481226890Sdim if (left) { 1482226890Sdim printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n"); 1483193326Sed error = EINVAL; 1484193326Sed } 1485193326Sed 1486263509Sdim return (error); 1487193326Sed} 1488226890Sdim 1489235633Sdim/* 1490235633Sdim * This is one of read routines. 1491235633Sdim * 1492198092Srdivacky * ntnode should be locked. 1493212904Sdim */ 1494245431Sdimint 1495245431Sdimntfs_readntvattr_plain( 1496235633Sdim struct ntfsmount * ntmp, 1497235633Sdim struct ntnode * ip, 1498235633Sdim struct ntvattr * vap, 1499235633Sdim off_t roff, 1500235633Sdim size_t rsize, 1501235633Sdim void *rdata, 1502235633Sdim size_t * initp, 1503235633Sdim struct uio *uio) 1504235633Sdim{ 1505235633Sdim int error = 0; 1506235633Sdim int off; 1507193326Sed 1508252723Sdim *initp = 0; 1509245431Sdim if (vap->va_flag & NTFS_AF_INRUN) { 1510235633Sdim int cnt; 1511235633Sdim cn_t ccn, ccl, cn, left, cl; 1512235633Sdim caddr_t data = rdata; 1513235633Sdim struct buf *bp; 1514235633Sdim size_t tocopy; 1515235633Sdim 1516235633Sdim ddprintf(("ntfs_readntvattr_plain: data in run: %ld chains\n", 1517235633Sdim vap->va_vruncnt)); 1518235633Sdim 1519235633Sdim off = roff; 1520235633Sdim left = rsize; 1521235633Sdim ccl = 0; 1522235633Sdim ccn = 0; 1523235633Sdim cnt = 0; 1524193326Sed while (left && (cnt < vap->va_vruncnt)) { 1525263509Sdim ccn = vap->va_vruncn[cnt]; 1526235633Sdim ccl = vap->va_vruncl[cnt]; 1527193326Sed 1528226890Sdim ddprintf(("ntfs_readntvattr_plain: " \ 1529235633Sdim "left %d, cn: 0x%x, cl: %d, off: %d\n", \ 1530235633Sdim (u_int32_t) left, (u_int32_t) ccn, \ 1531226890Sdim (u_int32_t) ccl, (u_int32_t) off)); 1532226890Sdim 1533226890Sdim if (ntfs_cntob(ccl) < off) { 1534226890Sdim off -= ntfs_cntob(ccl); 1535226890Sdim cnt++; 1536221345Sdim continue; 1537226890Sdim } 1538193326Sed if (ccn || ip->i_number == NTFS_BOOTINO) { 1539226890Sdim ccl -= ntfs_btocn(off); 1540198092Srdivacky cn = ccn + ntfs_btocn(off); 1541252723Sdim off = ntfs_btocnoff(off); 1542193326Sed 1543193326Sed while (left && ccl) { 1544193326Sed tocopy = min(left, 1545235633Sdim min(ntfs_cntob(ccl) - off, 1546193326Sed MAXBSIZE - off)); 1547193326Sed cl = ntfs_btocl(tocopy + off); 1548193326Sed ddprintf(("ntfs_readntvattr_plain: " \ 1549198092Srdivacky "read: cn: 0x%x cl: %d, " \ 1550193326Sed "off: %d len: %d, left: %d\n", 1551193326Sed (u_int32_t) cn, 1552193326Sed (u_int32_t) cl, 1553193326Sed (u_int32_t) off, 1554198092Srdivacky (u_int32_t) tocopy, 1555193326Sed (u_int32_t) left)); 1556193326Sed error = bread(ntmp->ntm_devvp, 1557193326Sed ntfs_cntobn(cn), 1558235633Sdim ntfs_cntob(cl), 1559218893Sdim NOCRED, &bp); 1560218893Sdim if (error) { 1561218893Sdim brelse(bp); 1562218893Sdim return (error); 1563218893Sdim } 1564218893Sdim if (uio) { 1565218893Sdim uiomove(bp->b_data + off, 1566218893Sdim tocopy, uio); 1567218893Sdim } else { 1568218893Sdim memcpy(data, bp->b_data + off, 1569193326Sed tocopy); 1570193326Sed } 1571193326Sed brelse(bp); 1572193326Sed data = data + tocopy; 1573193326Sed *initp += tocopy; 1574252723Sdim off = 0; 1575252723Sdim left -= tocopy; 1576252723Sdim cn += cl; 1577193326Sed ccl -= cl; 1578252723Sdim } 1579198092Srdivacky } else { 1580198092Srdivacky tocopy = min(left, ntfs_cntob(ccl) - off); 1581193326Sed ddprintf(("ntfs_readntvattr_plain: " 1582198092Srdivacky "hole: ccn: 0x%x ccl: %d, off: %d, " \ 1583193326Sed " len: %d, left: %d\n", 1584218893Sdim (u_int32_t) ccn, (u_int32_t) ccl, 1585193326Sed (u_int32_t) off, (u_int32_t) tocopy, 1586193326Sed (u_int32_t) left)); 1587193326Sed left -= tocopy; 1588193326Sed off = 0; 1589193326Sed if (uio) { 1590193326Sed size_t remains = tocopy; 1591193326Sed for(; remains; remains++) 1592193326Sed uiomove("", 1, uio); 1593193326Sed } else 1594193326Sed bzero(data, tocopy); 1595218893Sdim data = data + tocopy; 1596218893Sdim } 1597224145Sdim cnt++; 1598218893Sdim } 1599193326Sed if (left) { 1600198092Srdivacky printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n"); 1601193326Sed error = E2BIG; 1602198092Srdivacky } 1603193326Sed } else { 1604193326Sed ddprintf(("ntfs_readnvattr_plain: data is in mft record\n")); 1605193326Sed if (uio) 1606193326Sed uiomove(vap->va_datap + roff, rsize, uio); 1607193326Sed else 1608193326Sed memcpy(rdata, vap->va_datap + roff, rsize); 1609252723Sdim *initp += rsize; 1610252723Sdim } 1611193326Sed 1612193326Sed return (error); 1613193326Sed} 1614193326Sed 1615193326Sed/* 1616193326Sed * This is one of read routines. 1617193326Sed */ 1618193326Sedint 1619193326Sedntfs_readattr_plain( 1620198092Srdivacky struct ntfsmount * ntmp, 1621198092Srdivacky struct ntnode * ip, 1622193326Sed u_int32_t attrnum, 1623198092Srdivacky char *attrname, 1624193326Sed off_t roff, 1625218893Sdim size_t rsize, 1626193326Sed void *rdata, 1627193326Sed size_t * initp, 1628193326Sed struct uio *uio) 1629193326Sed{ 1630193326Sed size_t init; 1631193326Sed int error = 0; 1632193326Sed off_t off = roff, left = rsize, toread; 1633193326Sed caddr_t data = rdata; 1634193326Sed struct ntvattr *vap; 1635193326Sed *initp = 0; 1636193326Sed 1637193326Sed while (left) { 1638193326Sed error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1639193326Sed ntfs_btocn(off), &vap); 1640193326Sed if (error) 1641212904Sdim return (error); 1642212904Sdim toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1643193326Sed ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n", 1644212904Sdim (u_int32_t) off, (u_int32_t) toread, 1645212904Sdim (u_int32_t) vap->va_vcnstart, 1646193326Sed (u_int32_t) vap->va_vcnend)); 1647198092Srdivacky error = ntfs_readntvattr_plain(ntmp, ip, vap, 1648193326Sed off - ntfs_cntob(vap->va_vcnstart), 1649218893Sdim toread, data, &init, uio); 1650218893Sdim if (error) { 1651218893Sdim printf("ntfs_readattr_plain: " \ 1652212904Sdim "ntfs_readntvattr_plain failed: o: %d, s: %d\n", 1653218893Sdim (u_int32_t) off, (u_int32_t) toread); 1654235633Sdim printf("ntfs_readattr_plain: attrib: %d - %d\n", 1655224145Sdim (u_int32_t) vap->va_vcnstart, 1656218893Sdim (u_int32_t) vap->va_vcnend); 1657212904Sdim ntfs_ntvattrrele(vap); 1658193326Sed break; 1659193326Sed } 1660198092Srdivacky ntfs_ntvattrrele(vap); 1661212904Sdim left -= toread; 1662193326Sed off += toread; 1663212904Sdim data = data + toread; 1664193326Sed *initp += init; 1665193326Sed } 1666193326Sed 1667193326Sed return (error); 1668193326Sed} 1669193326Sed 1670193326Sed/* 1671193326Sed * This is one of read routines. 1672193326Sed */ 1673193326Sedint 1674193326Sedntfs_readattr( 1675212904Sdim struct ntfsmount * ntmp, 1676193326Sed struct ntnode * ip, 1677193326Sed u_int32_t attrnum, 1678218893Sdim char *attrname, 1679193326Sed off_t roff, 1680212904Sdim size_t rsize, 1681193326Sed void *rdata, 1682193326Sed struct uio *uio) 1683212904Sdim{ 1684212904Sdim int error = 0; 1685235633Sdim struct ntvattr *vap; 1686235633Sdim size_t init; 1687235633Sdim 1688235633Sdim ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n", 1689212904Sdim ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize)); 1690235633Sdim 1691212904Sdim error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap); 1692235633Sdim if (error) 1693235633Sdim return (error); 1694235633Sdim 1695235633Sdim if ((roff > vap->va_datalen) || 1696235633Sdim (roff + rsize > vap->va_datalen)) { 1697235633Sdim ddprintf(("ntfs_readattr: offset too big\n")); 1698235633Sdim ntfs_ntvattrrele(vap); 1699235633Sdim return (E2BIG); 1700235633Sdim } 1701212904Sdim if (vap->va_compression && vap->va_compressalg) { 1702235633Sdim u_int8_t *cup; 1703212904Sdim u_int8_t *uup; 1704235633Sdim off_t off = roff, left = rsize, tocopy; 1705212904Sdim caddr_t data = rdata; 1706212904Sdim cn_t cn; 1707212904Sdim 1708212904Sdim ddprintf(("ntfs_ntreadattr: compression: %d\n", 1709198092Srdivacky vap->va_compressalg)); 1710193326Sed 1711193326Sed MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL), 1712245431Sdim M_NTFSDECOMP, M_WAITOK); 1713193326Sed MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL), 1714193326Sed M_NTFSDECOMP, M_WAITOK); 1715193326Sed 1716193326Sed cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1)); 1717193326Sed off = roff - ntfs_cntob(cn); 1718193326Sed 1719193326Sed while (left) { 1720193326Sed error = ntfs_readattr_plain(ntmp, ip, attrnum, 1721193326Sed attrname, ntfs_cntob(cn), 1722252723Sdim ntfs_cntob(NTFS_COMPUNIT_CL), 1723252723Sdim cup, &init, NULL); 1724193326Sed if (error) 1725252723Sdim break; 1726252723Sdim 1727252723Sdim tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off); 1728235633Sdim 1729198092Srdivacky if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) { 1730198092Srdivacky if (uio) 1731198092Srdivacky uiomove(cup + off, tocopy, uio); 1732193326Sed else 1733198092Srdivacky memcpy(data, cup + off, tocopy); 1734193326Sed } else if (init == 0) { 1735218893Sdim if (uio) { 1736193326Sed size_t remains = tocopy; 1737193326Sed for(; remains; remains--) 1738207619Srdivacky uiomove("", 1, uio); 1739207619Srdivacky } 1740207619Srdivacky else 1741207619Srdivacky bzero(data, tocopy); 1742207619Srdivacky } else { 1743235633Sdim error = ntfs_uncompunit(ntmp, uup, cup); 1744207619Srdivacky if (error) 1745207619Srdivacky break; 1746207619Srdivacky if (uio) 1747207619Srdivacky uiomove(uup + off, tocopy, uio); 1748207619Srdivacky else 1749207619Srdivacky memcpy(data, uup + off, tocopy); 1750235633Sdim } 1751207619Srdivacky 1752207619Srdivacky left -= tocopy; 1753207619Srdivacky data = data + tocopy; 1754207619Srdivacky off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL); 1755207619Srdivacky cn += NTFS_COMPUNIT_CL; 1756207619Srdivacky } 1757207619Srdivacky 1758207619Srdivacky FREE(uup, M_NTFSDECOMP); 1759207619Srdivacky FREE(cup, M_NTFSDECOMP); 1760207619Srdivacky } else 1761207619Srdivacky error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname, 1762207619Srdivacky roff, rsize, rdata, &init, uio); 1763207619Srdivacky ntfs_ntvattrrele(vap); 1764207619Srdivacky return (error); 1765207619Srdivacky} 1766207619Srdivacky 1767207619Srdivacky#if UNUSED_CODE 1768207619Srdivackyint 1769207619Srdivackyntfs_parserun( 1770207619Srdivacky cn_t * cn, 1771207619Srdivacky cn_t * cl, 1772235633Sdim u_int8_t * run, 1773207619Srdivacky u_long len, 1774207619Srdivacky u_long *off) 1775235633Sdim{ 1776207619Srdivacky u_int8_t sz; 1777207619Srdivacky int i; 1778235633Sdim 1779207619Srdivacky if (NULL == run) { 1780207619Srdivacky printf("ntfs_parsetun: run == NULL\n"); 1781207619Srdivacky return (EINVAL); 1782207619Srdivacky } 1783235633Sdim sz = run[(*off)++]; 1784207619Srdivacky if (0 == sz) { 1785207619Srdivacky printf("ntfs_parserun: trying to go out of run\n"); 1786235633Sdim return (E2BIG); 1787207619Srdivacky } 1788207619Srdivacky *cl = 0; 1789235633Sdim if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1790207619Srdivacky printf("ntfs_parserun: " \ 1791207619Srdivacky "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1792235633Sdim sz, len, *off); 1793207619Srdivacky return (EINVAL); 1794235633Sdim } 1795207619Srdivacky for (i = 0; i < (sz & 0xF); i++) 1796235633Sdim *cl += (u_int32_t) run[(*off)++] << (i << 3); 1797207619Srdivacky 1798235633Sdim sz >>= 4; 1799207619Srdivacky if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1800207619Srdivacky printf("ntfs_parserun: " \ 1801207619Srdivacky "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1802235633Sdim sz, len, *off); 1803207619Srdivacky return (EINVAL); 1804207619Srdivacky } 1805207619Srdivacky for (i = 0; i < (sz & 0xF); i++) 1806207619Srdivacky *cn += (u_int32_t) run[(*off)++] << (i << 3); 1807207619Srdivacky 1808235633Sdim return (0); 1809207619Srdivacky} 1810235633Sdim#endif 1811207619Srdivacky 1812207619Srdivacky/* 1813235633Sdim * Process fixup routine on given buffer. 1814207619Srdivacky */ 1815207619Srdivackyint 1816207619Srdivackyntfs_procfixups( 1817207619Srdivacky struct ntfsmount * ntmp, 1818207619Srdivacky u_int32_t magic, 1819207619Srdivacky caddr_t buf, 1820207619Srdivacky size_t len) 1821207619Srdivacky{ 1822207619Srdivacky struct fixuphdr *fhp = (struct fixuphdr *) buf; 1823207619Srdivacky int i; 1824207619Srdivacky u_int16_t fixup; 1825207619Srdivacky u_int16_t *fxp; 1826235633Sdim u_int16_t *cfxp; 1827207619Srdivacky 1828207619Srdivacky if (fhp->fh_magic != magic) { 1829207619Srdivacky printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n", 1830235633Sdim fhp->fh_magic, magic); 1831207619Srdivacky return (EINVAL); 1832207619Srdivacky } 1833207619Srdivacky if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) { 1834235633Sdim printf("ntfs_procfixups: " \ 1835207619Srdivacky "bad fixups number: %d for %ld bytes block\n", 1836235633Sdim fhp->fh_fnum, (long)len); /* XXX printf kludge */ 1837207619Srdivacky return (EINVAL); 1838207619Srdivacky } 1839207619Srdivacky if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) { 1840207619Srdivacky printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff); 1841235633Sdim return (EINVAL); 1842207619Srdivacky } 1843235633Sdim fxp = (u_int16_t *) (buf + fhp->fh_foff); 1844252723Sdim cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2); 1845252723Sdim fixup = *fxp++; 1846207619Srdivacky for (i = 1; i < fhp->fh_fnum; i++, fxp++) { 1847207619Srdivacky if (*cfxp != fixup) { 1848207619Srdivacky printf("ntfs_procfixups: fixup %d doesn't match\n", i); 1849235633Sdim return (EINVAL); 1850207619Srdivacky } 1851207619Srdivacky *cfxp = *fxp; 1852207619Srdivacky ((caddr_t) cfxp) += ntmp->ntm_bps; 1853207619Srdivacky } 1854207619Srdivacky return (0); 1855207619Srdivacky} 1856207619Srdivacky 1857235633Sdim#if UNUSED_CODE 1858263509Sdimint 1859207619Srdivackyntfs_runtocn( 1860245431Sdim cn_t * cn, 1861207619Srdivacky struct ntfsmount * ntmp, 1862207619Srdivacky u_int8_t * run, 1863207619Srdivacky u_long len, 1864207619Srdivacky cn_t vcn) 1865235633Sdim{ 1866207619Srdivacky cn_t ccn = 0; 1867207619Srdivacky cn_t ccl = 0; 1868235633Sdim u_long off = 0; 1869263509Sdim int error = 0; 1870235633Sdim 1871245431Sdim#if NTFS_DEBUG 1872245431Sdim int i; 1873207619Srdivacky printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n", 1874263509Sdim run, len, (u_long) vcn); 1875207619Srdivacky printf("ntfs_runtocn: run: "); 1876207619Srdivacky for (i = 0; i < len; i++) 1877207619Srdivacky printf("0x%02x ", run[i]); 1878207619Srdivacky printf("\n"); 1879207619Srdivacky#endif 1880207619Srdivacky 1881207619Srdivacky if (NULL == run) { 1882207619Srdivacky printf("ntfs_runtocn: run == NULL\n"); 1883207619Srdivacky return (EINVAL); 1884235633Sdim } 1885207619Srdivacky do { 1886207619Srdivacky if (run[off] == 0) { 1887207619Srdivacky printf("ntfs_runtocn: vcn too big\n"); 1888207619Srdivacky return (E2BIG); 1889207619Srdivacky } 1890207619Srdivacky vcn -= ccl; 1891235633Sdim error = ntfs_parserun(&ccn, &ccl, run, len, &off); 1892223017Sdim if (error) { 1893207619Srdivacky printf("ntfs_runtocn: ntfs_parserun failed\n"); 1894223017Sdim return (error); 1895207619Srdivacky } 1896207619Srdivacky } while (ccl <= vcn); 1897207619Srdivacky *cn = ccn + vcn; 1898207619Srdivacky return (0); 1899207619Srdivacky} 1900207619Srdivacky#endif 1901235633Sdim 1902207619Srdivacky/* 1903207619Srdivacky * this initializes toupper table & dependant variables to be ready for 1904207619Srdivacky * later work 1905207619Srdivacky */ 1906207619Srdivackyvoid 1907207619Srdivackyntfs_toupper_init() 1908207619Srdivacky{ 1909207619Srdivacky ntfs_toupper_tab = (wchar *) NULL; 1910207619Srdivacky lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0); 1911223017Sdim ntfs_toupper_usecount = 0; 1912223017Sdim} 1913223017Sdim 1914207619Srdivackyvoid 1915207619Srdivackyntfs_toupper_destroy(void) 1916207619Srdivacky{ 1917207619Srdivacky 1918207619Srdivacky lockdestroy(&ntfs_toupper_lock); 1919207619Srdivacky} 1920235633Sdim 1921207619Srdivacky/* 1922207619Srdivacky * if the ntfs_toupper_tab[] is filled already, just raise use count; 1923207619Srdivacky * otherwise read the data from the filesystem we are currently mounting 1924207619Srdivacky */ 1925252723Sdimint 1926252723Sdimntfs_toupper_use(mp, ntmp) 1927207619Srdivacky struct mount *mp; 1928207619Srdivacky struct ntfsmount *ntmp; 1929207619Srdivacky{ 1930207619Srdivacky int error = 0; 1931207619Srdivacky struct vnode *vp; 1932207619Srdivacky 1933218893Sdim /* get exclusive access */ 1934218893Sdim lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL, NULL); 1935218893Sdim 1936218893Sdim /* only read the translation data from a file if it hasn't been 1937218893Sdim * read already */ 1938218893Sdim if (ntfs_toupper_tab) 1939207619Srdivacky goto out; 1940207619Srdivacky 1941221345Sdim /* 1942221345Sdim * Read in Unicode lowercase -> uppercase translation file. 1943221345Sdim * XXX for now, just the first 256 entries are used anyway, 1944221345Sdim * so don't bother reading more 1945193326Sed */ 1946200583Srdivacky MALLOC(ntfs_toupper_tab, wchar *, 65536 * sizeof(wchar), 1947193326Sed M_NTFSRDATA, M_WAITOK); 1948193326Sed 1949193326Sed if ((error = VFS_VGET(mp, NTFS_UPCASEINO, LK_EXCLUSIVE, &vp))) 1950198092Srdivacky goto out; 1951193326Sed error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 1952221345Sdim 0, 65536*sizeof(wchar), (char *) ntfs_toupper_tab, NULL); 1953221345Sdim vput(vp); 1954221345Sdim 1955221345Sdim out: 1956193326Sed ntfs_toupper_usecount++; 1957193326Sed lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL, NULL); 1958218893Sdim return (error); 1959224145Sdim} 1960218893Sdim 1961235633Sdim/* 1962235633Sdim * lower the use count and if it reaches zero, free the memory 1963235633Sdim * tied by toupper table 1964200583Srdivacky */ 1965193326Sedvoid 1966193326Sedntfs_toupper_unuse() 1967221345Sdim{ 1968221345Sdim /* get exclusive access */ 1969221345Sdim lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL, NULL); 1970221345Sdim 1971193326Sed ntfs_toupper_usecount--; 1972193326Sed if (ntfs_toupper_usecount == 0) { 1973218893Sdim FREE(ntfs_toupper_tab, M_NTFSRDATA); 1974224145Sdim ntfs_toupper_tab = NULL; 1975218893Sdim } 1976235633Sdim#ifdef DIAGNOSTIC 1977235633Sdim else if (ntfs_toupper_usecount < 0) { 1978235633Sdim panic("ntfs_toupper_unuse(): use count negative: %d\n", 1979193326Sed ntfs_toupper_usecount); 1980193326Sed } 1981193326Sed#endif 1982193326Sed 1983221345Sdim /* release the lock */ 1984221345Sdim lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL, NULL); 1985193326Sed} 1986221345Sdim 1987235633Sdimint 1988221345Sdimntfs_u28_init( 1989235633Sdim struct ntfsmount *ntmp, 1990193326Sed wchar *u2w) 1991235633Sdim{ 1992193326Sed char ** u28; 1993198893Srdivacky int i, j, h, l; 1994198893Srdivacky 1995200583Srdivacky MALLOC(u28, char **, 256 * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO); 1996193326Sed 1997198893Srdivacky for (i=0; i<256; i++) { 1998193326Sed h = (u2w[i] >> 8) & 0xFF; 1999193326Sed l = (u2w[i]) &0xFF; 2000193326Sed 2001193326Sed if (u28[h] == NULL) { 2002193326Sed MALLOC(u28[h], char *, 256 * sizeof(char), M_TEMP, M_WAITOK); 2003193326Sed for (j=0; j<256; j++) 2004221345Sdim u28[h][j] = '_'; 2005193326Sed } 2006193326Sed 2007235633Sdim u28[h][l] = i & 0xFF; 2008235633Sdim } 2009235633Sdim 2010235633Sdim ntmp->ntm_u28 = u28; 2011200583Srdivacky 2012200583Srdivacky return (0); 2013235633Sdim} 2014193326Sed 2015193326Sedint 2016193326Sedntfs_u28_uninit(struct ntfsmount *ntmp) 2017193326Sed{ 2018193326Sed char ** u28; 2019193326Sed int i; 2020193326Sed 2021193326Sed if (ntmp->ntm_u28 == NULL) 2022193326Sed return (0); 2023193326Sed 2024193326Sed u28 = ntmp->ntm_u28; 2025193326Sed 2026193326Sed for (i=0; i<256; i++) 2027193326Sed if (u28[i] != NULL) 2028252723Sdim FREE(u28[i], M_TEMP); 2029252723Sdim 2030193326Sed FREE(u28, M_TEMP); 2031198092Srdivacky 2032221345Sdim return (0); 2033193326Sed} 2034198092Srdivacky 2035193326Sedint 2036218893Sdimntfs_82u_init( 2037193326Sed struct ntfsmount *ntmp, 2038193326Sed u_int16_t *u2w) 2039193326Sed{ 2040193326Sed wchar * _82u; 2041193326Sed int i; 2042193326Sed 2043193326Sed MALLOC(_82u, wchar *, 256 * sizeof(wchar), M_TEMP, M_WAITOK); 2044193326Sed 2045193326Sed if (u2w == NULL) { 2046198092Srdivacky for (i=0; i<256; i++) 2047193326Sed _82u[i] = i; 2048193326Sed } else { 2049193326Sed for (i=0; i<128; i++) 2050218893Sdim _82u[i] = i; 2051193326Sed for (i=0; i<128; i++) 2052218893Sdim _82u[i+128] = u2w[i]; 2053193326Sed } 2054218893Sdim 2055224145Sdim ntmp->ntm_82u = _82u; 2056224145Sdim 2057218893Sdim return (0); 2058218893Sdim} 2059193326Sed 2060193326Sedint 2061193326Sedntfs_82u_uninit(struct ntfsmount *ntmp) 2062193326Sed{ 2063198092Srdivacky FREE(ntmp->ntm_82u, M_TEMP); 2064193326Sed return (0); 2065193326Sed} 2066193326Sed 2067193326Sed/* 2068193326Sed * maps the Unicode char to 8bit equivalent 2069193326Sed * XXX currently only gets lower 8bit from the Unicode char 2070193326Sed * and substitutes a '_' for it if the result would be '\0'; 2071193326Sed * something better has to be definitely though out 2072193326Sed */ 2073193326Sedchar 2074193326Sedntfs_u28( 2075193326Sed struct ntfsmount *ntmp, 2076193326Sed wchar wc) 2077193326Sed{ 2078193326Sed char * p; 2079193326Sed 2080193326Sed p = ntmp->ntm_u28[(wc>>8)&0xFF]; 2081193326Sed if (p == NULL) 2082193326Sed return ('_'); 2083193326Sed return (p[wc&0xFF]); 2084198092Srdivacky} 2085198092Srdivacky 2086193326Sed