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