ntfs_subr.c revision 43552
1/*-
2 * Copyright (c) 1998, 1999 Semen Ustimenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$Id: ntfs_subr.c,v 1.9 1999/02/02 01:54:54 semen Exp $
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/namei.h>
32#include <sys/proc.h>
33#include <sys/kernel.h>
34#include <sys/vnode.h>
35#include <sys/mount.h>
36#include <sys/buf.h>
37#include <sys/file.h>
38#include <sys/malloc.h>
39#include <machine/clock.h>
40
41#include <miscfs/specfs/specdev.h>
42
43/* #define NTFS_DEBUG 1 */
44#include <ntfs/ntfs.h>
45#include <ntfs/ntfsmount.h>
46#include <ntfs/ntfs_inode.h>
47#include <ntfs/ntfs_subr.h>
48#include <ntfs/ntfs_compr.h>
49
50#if __FreeBSD_version >= 300000
51MALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information");
52MALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
53MALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
54MALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
55#endif
56
57int
58ntfs_ntvattrrele(
59		 struct ntvattr * vap)
60{
61	dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
62		 vap->va_ip->i_number, vap->va_type));
63
64	vrele(NTTOV(vap->va_ip));
65
66	return (0);
67}
68
69int
70ntfs_ntvattrget(
71		struct ntfsmount * ntmp,
72		struct ntnode * ip,
73		u_int32_t type,
74		char *name,
75		cn_t vcn,
76		struct ntvattr ** vapp)
77{
78	int             error;
79	struct ntvattr *vap;
80	struct ntvattr *lvap = NULL;
81	struct attr_attrlist *aalp;
82	struct attr_attrlist *nextaalp;
83	caddr_t         alpool;
84	int             len, namelen;
85
86	*vapp = NULL;
87
88	if (name) {
89		dprintf(("ntfs_ntvattrget: " \
90			 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
91			 ip->i_number, type, name, (u_int32_t) vcn));
92		namelen = strlen(name);
93	} else {
94		dprintf(("ntfs_ntvattrget: " \
95			 "ino: %d, type: 0x%x, vcn: %d\n", \
96			 ip->i_number, type, (u_int32_t) vcn));
97		name = "";
98		namelen = 0;
99	}
100
101	if((ip->i_flag & IN_LOADED) == 0) {
102		dprintf(("ntfs_ntvattrget: node not loaded, ino: %d\n",
103		       ip->i_number));
104		error = ntfs_loadnode(ntmp,ip);
105		if(error) {
106			printf("ntfs_ntvattrget: FAILED TO LOAD INO: %d\n",
107			       ip->i_number);
108			return (error);
109		}
110	}
111
112	for (vap = ip->i_vattrp; vap; vap = vap->va_nextp) {
113		ddprintf(("type: 0x%x, vcn: %d - %d\n", \
114			  vap->va_type, (u_int32_t) vap->va_vcnstart, \
115			  (u_int32_t) vap->va_vcnend));
116		if ((vap->va_type == type) &&
117		    (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
118		    (vap->va_namelen == namelen) &&
119		    (!strncmp(name, vap->va_name, namelen))) {
120			*vapp = vap;
121#if __FreeBSD_version >= 300000
122			VREF(NTTOV(vap->va_ip));
123#else
124			/*
125			 * In RELENG_2_2 vref can call vfs_object_create(...)
126			 * who calls vgetattr, who calls ntfs_getattr, who
127			 * calls ntfs_ntvattrget, who calls vref... :-( This
128			 * hack is to avoid it.   XXX
129			 */
130			NTTOV(vap->va_ip)->v_usecount++;
131#endif
132			return (0);
133		}
134		if (vap->va_type == NTFS_A_ATTRLIST)
135			lvap = vap;
136	}
137
138	if (!lvap) {
139		dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
140		       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
141		       ip->i_number, type, name, (u_int32_t) vcn));
142		return (ENOENT);
143	}
144	/* Scan $ATTRIBUTE_LIST for requested attribute */
145	len = lvap->va_datalen;
146	MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK);
147	error = ntfs_breadntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len);
148	if (error)
149		goto out;
150
151	aalp = (struct attr_attrlist *) alpool;
152	nextaalp = NULL;
153
154	while (len > 0) {
155		dprintf(("ntfs_ntvattrget: " \
156			 "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
157			 aalp->al_inumber, aalp->al_type, \
158			 (u_int32_t) aalp->al_vcnstart));
159
160		if (len > aalp->reclen) {
161			nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
162		} else {
163			nextaalp = NULL;
164		}
165		len -= aalp->reclen;
166
167#define AALPCMP(aalp,type,name,namelen) (				\
168  (aalp->al_type == type) && (aalp->al_namelen == namelen) &&		\
169  !uastrcmp(aalp->al_name,aalp->al_namelen,name,namelen) )
170
171		if (AALPCMP(aalp, type, name, namelen) &&
172		    (!nextaalp || (nextaalp->al_vcnstart > vcn) ||
173		     !AALPCMP(nextaalp, type, name, namelen))) {
174			struct vnode   *newvp;
175			struct ntnode  *newip;
176
177			dprintf(("ntfs_ntvattrget: attrbute in ino: %d\n",
178				 aalp->al_inumber));
179
180			error = VFS_VGET(ntmp->ntm_mountp, aalp->al_inumber,
181					 &newvp);
182			if (error) {
183				printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
184				       aalp->al_inumber);
185				goto out;
186			}
187			newip = VTONT(newvp);
188			if(~newip->i_flag & IN_LOADED) {
189				dprintf(("ntfs_ntvattrget: node not loaded," \
190					 " ino: %d\n", newip->i_number));
191				error = ntfs_loadnode(ntmp,ip);
192				if(error) {
193					printf("ntfs_ntvattrget: CAN'T LOAD " \
194					       "INO: %d\n", newip->i_number);
195					vput(newvp);
196					goto out;
197				}
198			}
199			for (vap = newip->i_vattrp; vap; vap = vap->va_nextp) {
200				if ((vap->va_type == type) &&
201				    (vap->va_vcnstart <= vcn) &&
202				    (vap->va_vcnend >= vcn) &&
203				    (vap->va_namelen == namelen) &&
204				  (!strncmp(name, vap->va_name, namelen))) {
205					*vapp = vap;
206#if __FreeBSD_version >= 300000
207					VREF(NTTOV(vap->va_ip));
208#else
209					/* See comment above */
210					NTTOV(vap->va_ip)->v_usecount++;
211#endif
212					vput(newvp);
213					error = 0;
214					goto out;
215				}
216				if (vap->va_type == NTFS_A_ATTRLIST)
217					lvap = vap;
218			}
219			printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
220			vput(newvp);
221			break;
222		}
223#undef AALPCMP
224		aalp = nextaalp;
225	}
226	error = ENOENT;
227
228	dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
229	       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
230	       ip->i_number, type, name, (u_int32_t) vcn));
231out:
232	FREE(alpool, M_TEMP);
233
234	return (error);
235}
236
237int
238ntfs_loadnode(
239	      struct ntfsmount * ntmp,
240	      struct ntnode * ip)
241{
242	struct filerec  *mfrp;
243	daddr_t         bn;
244	int		error,off;
245	struct attr    *ap;
246	struct ntvattr**vapp;
247
248	dprintf(("ntfs_loadnode: loading ino: %d\n",ip->i_number));
249
250	MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec),
251	       M_TEMP, M_WAITOK);
252
253	if (ip->i_number < NTFS_SYSNODESNUM) {
254		struct buf     *bp;
255
256		dprintf(("ntfs_loadnode: read system node\n"));
257
258		bn = ntfs_cntobn(ntmp->ntm_mftcn) +
259			ntmp->ntm_bpmftrec * ip->i_number;
260
261		error = bread(ntmp->ntm_devvp,
262			      bn, ntfs_bntob(ntmp->ntm_bpmftrec),
263			      NOCRED, &bp);
264		if (error) {
265			printf("ntfs_loadnode: BREAD FAILED\n");
266			brelse(bp);
267			goto out;
268		}
269		memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
270		bqrelse(bp);
271	} else {
272		struct vnode   *vp;
273
274		vp = ntmp->ntm_sysvn[NTFS_MFTINO];
275		error = ntfs_breadattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
276			       ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
277			       ntfs_bntob(ntmp->ntm_bpmftrec), mfrp);
278		if (error) {
279			printf("ntfs_loadnode: ntfs_breadattr failed\n");
280			goto out;
281		}
282	}
283	/* Check if magic and fixups are correct */
284	error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
285				ntfs_bntob(ntmp->ntm_bpmftrec));
286	if (error) {
287		printf("ntfs_loadnode: BAD MFT RECORD %d\n",
288		       (u_int32_t) ip->i_number);
289		goto out;
290	}
291
292	dprintf(("ntfs_loadnode: load attrs for ino: %d\n",ip->i_number));
293	off = mfrp->fr_attroff;
294	ap = (struct attr *) ((caddr_t)mfrp + off);
295	vapp = &ip->i_vattrp;
296	while (ap->a_hdr.a_type != -1) {
297		error = ntfs_attrtontvattr(ntmp, vapp, ap);
298		if (error)
299			break;
300		(*vapp)->va_ip = ip;
301		vapp = &((*vapp)->va_nextp);
302
303		off += ap->a_hdr.reclen;
304		ap = (struct attr *) ((caddr_t)mfrp + off);
305	}
306	if (error) {
307		printf("ntfs_loadnode: failed to load attr ino: %d\n",
308		       ip->i_number);
309		goto out;
310	}
311
312	ip->i_mainrec = mfrp->fr_mainrec;
313	ip->i_nlink = mfrp->fr_nlink;
314	ip->i_frflag = mfrp->fr_flags;
315
316	ip->i_flag |= IN_LOADED;
317
318	if (ip->i_mainrec == 0) {
319		struct ntvattr *vap;
320
321		if (ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap) == 0){
322			ip->i_times = vap->va_a_name->n_times;
323			ip->i_pnumber = vap->va_a_name->n_pnumber;
324			ip->i_fflag = vap->va_a_name->n_flag;
325
326			ntfs_ntvattrrele(vap);
327		}
328
329		if ((ip->i_fflag & NTFS_FFLAG_DIR) && (ip->i_defattr == 0)) {
330			struct ntvattr *irvap;
331
332			ip->i_type = VDIR;
333			ip->i_defattr = NTFS_A_INDXROOT;
334			ip->i_defattrname = "$I30";
335			error = ntfs_ntvattrget(ntmp, ip,
336						NTFS_A_INDXROOT, "$I30",
337						0, &irvap);
338			if(error == 0) {
339				ip->i_dirblsz = irvap->va_a_iroot->ir_size;
340				MALLOC(ip->i_dirblbuf, caddr_t,
341				       max(irvap->va_datalen,ip->i_dirblsz),
342				       M_NTFSDIR, M_WAITOK);
343
344				ntfs_ntvattrrele(irvap);
345			}
346			ip->i_size = 0;
347			ip->i_allocated = 0;
348			error = 0;
349		} else {
350			ip->i_type = VREG;
351			if(ip->i_defattr == 0) {
352				ip->i_defattr = NTFS_A_DATA;
353				ip->i_defattrname = NULL;
354			}
355
356			ntfs_filesize(ntmp, ip, &ip->i_size, &ip->i_allocated);
357		}
358	}
359
360	if (NTTOV(ip)) {
361		if (ip->i_number == NTFS_ROOTINO)
362			NTTOV(ip)->v_flag |= VROOT;
363		if (ip->i_number < NTFS_SYSNODESNUM)
364			NTTOV(ip)->v_flag |= VSYSTEM;
365		NTTOV(ip)->v_type = ip->i_type;
366	}
367out:
368	FREE(mfrp, M_TEMP);
369	return (error);
370}
371
372
373int
374ntfs_ntget(
375	   struct ntfsmount * ntmp,
376	   ino_t ino,
377	   struct ntnode ** ipp)
378{
379	struct ntnode  *ip;
380
381	dprintf(("ntfs_ntget: allocate ntnode %d\n", ino));
382	*ipp = NULL;
383
384	MALLOC(ip, struct ntnode *, sizeof(struct ntnode),
385	       M_NTFSNODE, M_WAITOK);
386	bzero((caddr_t) ip, sizeof(struct ntnode));
387
388	/* Generic initialization */
389	ip->i_mp = ntmp;
390	ip->i_number = ino;
391	ip->i_dev = ntmp->ntm_dev;
392	ip->i_uid = ntmp->ntm_uid;
393	ip->i_gid = ntmp->ntm_gid;
394	ip->i_mode = ntmp->ntm_mode;
395
396	/* Setup internal pointers */
397	ip->i_vattrp = NULL;
398	ip->i_devvp = ntmp->ntm_devvp;
399
400	*ipp = ip;
401	dprintf(("ntfs_ntget: allocated ntnode %d ok\n", ino));
402
403	return (0);
404}
405
406void
407ntfs_ntrele(
408	    struct ntnode * ip)
409{
410	struct ntvattr *vap;
411
412	dprintf(("ntfs_ntrele: rele ntnode %d\n", ip->i_number));
413	while (ip->i_vattrp) {
414		vap = ip->i_vattrp;
415		ip->i_vattrp = vap->va_nextp;
416		ntfs_freentvattr(vap);
417	}
418	if(ip->i_flag & IN_AATTRNAME) FREE(ip->i_defattrname,M_TEMP);
419	dprintf(("ntfs_ntrele: rele ntnode %d ok\n", ip->i_number));
420	FREE(ip, M_NTFSNODE);
421}
422
423void
424ntfs_freentvattr(
425		 struct ntvattr * vap)
426{
427	if (vap->va_flag & NTFS_AF_INRUN) {
428		if (vap->va_vruncn)
429			FREE(vap->va_vruncn, M_NTFSRUN);
430		if (vap->va_vruncl)
431			FREE(vap->va_vruncl, M_NTFSRUN);
432	} else {
433		if (vap->va_datap)
434			FREE(vap->va_datap, M_NTFSRDATA);
435	}
436	FREE(vap, M_NTFSNTVATTR);
437}
438
439int
440ntfs_attrtontvattr(
441		   struct ntfsmount * ntmp,
442		   struct ntvattr ** rvapp,
443		   struct attr * rap)
444{
445	int             error, i;
446	struct ntvattr *vap;
447
448	error = 0;
449	*rvapp = NULL;
450
451	MALLOC(vap, struct ntvattr *, sizeof(*vap), M_NTFSNTVATTR, M_WAITOK);
452	vap->va_ip = NULL;
453	vap->va_flag = rap->a_hdr.a_flag;
454	vap->va_type = rap->a_hdr.a_type;
455	vap->va_compression = rap->a_hdr.a_compression;
456	vap->va_nextp = NULL;
457	vap->va_index = rap->a_hdr.a_index;
458
459	ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
460
461	vap->va_namelen = rap->a_hdr.a_namelen;
462	if (rap->a_hdr.a_namelen) {
463		wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
464		ddprintf((", name:["));
465		for (i = 0; i < vap->va_namelen; i++) {
466			vap->va_name[i] = unp[i];
467			ddprintf(("%c", vap->va_name[i]));
468		}
469		ddprintf(("]"));
470	}
471	if (vap->va_flag & NTFS_AF_INRUN) {
472		ddprintf((", nonres."));
473		vap->va_datalen = rap->a_nr.a_datalen;
474		vap->va_allocated = rap->a_nr.a_allocated;
475		vap->va_vcnstart = rap->a_nr.a_vcnstart;
476		vap->va_vcnend = rap->a_nr.a_vcnend;
477		vap->va_compressalg = rap->a_nr.a_compressalg;
478		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
479				       &(vap->va_vruncnt),
480				       (caddr_t) rap + rap->a_nr.a_dataoff);
481	} else {
482		vap->va_compressalg = 0;
483		ddprintf((", res."));
484		vap->va_datalen = rap->a_r.a_datalen;
485		vap->va_allocated = rap->a_r.a_datalen;
486		vap->va_vcnstart = 0;
487		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
488		MALLOC(vap->va_datap, caddr_t, vap->va_datalen,
489		       M_NTFSRDATA, M_WAITOK);
490		memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
491		       rap->a_r.a_datalen);
492	}
493	ddprintf((", len: %d", vap->va_datalen));
494
495	if (error)
496		FREE(vap, M_NTFSNTVATTR);
497	else
498		*rvapp = vap;
499
500	ddprintf(("\n"));
501
502	return (error);
503}
504
505int
506ntfs_runtovrun(
507	       cn_t ** rcnp,
508	       cn_t ** rclp,
509	       u_int32_t * rcntp,
510	       u_int8_t * run)
511{
512	u_int32_t       off;
513	u_int32_t       sz, i;
514	cn_t           *cn;
515	cn_t           *cl;
516	u_int32_t       cnt;
517	u_int64_t       prev;
518
519	off = 0;
520	cnt = 0;
521	i = 0;
522	while (run[off]) {
523		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
524		cnt++;
525	}
526	MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
527	MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
528
529	off = 0;
530	cnt = 0;
531	prev = 0;
532	while (run[off]) {
533		u_int64_t       tmp;
534
535		sz = run[off++];
536		cl[cnt] = 0;
537
538		for (i = 0; i < (sz & 0xF); i++)
539			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
540
541		sz >>= 4;
542		if (run[off + sz - 1] & 0x80) {
543			tmp = ((u_int64_t) - 1) << (sz << 3);
544			for (i = 0; i < sz; i++)
545				tmp |= (u_int64_t) run[off++] << (i << 3);
546		} else {
547			tmp = 0;
548			for (i = 0; i < sz; i++)
549				tmp |= (u_int64_t) run[off++] << (i << 3);
550		}
551		if (tmp)
552			prev = cn[cnt] = prev + tmp;
553		else
554			cn[cnt] = tmp;
555
556		cnt++;
557	}
558	*rcnp = cn;
559	*rclp = cl;
560	*rcntp = cnt;
561	return (0);
562}
563
564
565wchar
566ntfs_toupper(
567	     struct ntfsmount * ntmp,
568	     wchar wc)
569{
570	return (ntmp->ntm_upcase[wc & 0xFF]);
571}
572
573int
574ntfs_uustricmp(
575	       struct ntfsmount * ntmp,
576	       wchar * str1,
577	       int str1len,
578	       wchar * str2,
579	       int str2len)
580{
581	int             i;
582	int             res;
583
584	for (i = 0; i < str1len && i < str2len; i++) {
585		res = (int) ntfs_toupper(ntmp, str1[i]) -
586			(int) ntfs_toupper(ntmp, str2[i]);
587		if (res)
588			return res;
589	}
590	return (str1len - str2len);
591}
592
593int
594ntfs_uastricmp(
595	       struct ntfsmount * ntmp,
596	       wchar * str1,
597	       int str1len,
598	       char *str2,
599	       int str2len)
600{
601	int             i;
602	int             res;
603
604	for (i = 0; i < str1len && i < str2len; i++) {
605		res = (int) ntfs_toupper(ntmp, str1[i]) -
606			(int) ntfs_toupper(ntmp, (wchar) str2[i]);
607		if (res)
608			return res;
609	}
610	return (str1len - str2len);
611}
612
613int
614ntfs_uastrcmp(
615	      struct ntfsmount * ntmp,
616	      wchar * str1,
617	      int str1len,
618	      char *str2,
619	      int str2len)
620{
621	int             i;
622	int             res;
623
624	for (i = 0; (i < str1len) && (i < str2len); i++) {
625		res = ((int) str1[i]) - ((int) str2[i]);
626		if (res)
627			return res;
628	}
629	return (str1len - str2len);
630}
631
632int
633ntfs_ntlookupattr(
634		struct ntfsmount * ntmp,
635		char * name,
636		int namelen,
637		int *type,
638		char **attrname)
639{
640	char *sys;
641	int syslen,i;
642	struct ntvattrdef *adp;
643
644	if (namelen == 0)
645		return (0);
646
647	if (name[0] == '$') {
648		sys = name;
649		for (syslen = 0; syslen < namelen; syslen++) {
650			if(sys[syslen] == ':') {
651				name++;
652				namelen--;
653				break;
654			}
655		}
656		name += syslen;
657		namelen -= syslen;
658
659		adp = ntmp->ntm_ad;
660		for (i = 0; i < ntmp->ntm_adnum; i++){
661			if((syslen == adp->ad_namelen) &&
662			   (!strncmp(sys,adp->ad_name,syslen))) {
663				*type = adp->ad_type;
664				if(namelen) {
665					MALLOC((*attrname), char *, namelen,
666						M_TEMP, M_WAITOK);
667					memcpy((*attrname), name, namelen);
668					(*attrname)[namelen] = '\0';
669				}/* else
670					(*attrname) = NULL;*/
671				return (0);
672			}
673			adp++;
674		}
675		return (ENOENT);
676	}
677
678	if(namelen) {
679		MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK);
680		memcpy((*attrname), name, namelen);
681		(*attrname)[namelen] = '\0';
682	}
683
684	return (0);
685}
686/*
687 * Lookup specifed node for filename, matching cnp, return filled ntnode.
688 */
689int
690ntfs_ntlookup(
691	      struct ntfsmount * ntmp,
692	      struct ntnode * ip,
693	      struct componentname * cnp,
694	      struct ntnode ** ipp)
695{
696	struct ntvattr *vap;	/* Root attribute */
697	cn_t            cn;	/* VCN in current attribute */
698	caddr_t         rdbuf;	/* Buffer to read directory's blocks  */
699	u_int32_t       blsize;
700	u_int32_t       rdsize;	/* Length of data to read from current block */
701	struct attr_indexentry *iep;
702	int             error, res, anamelen, fnamelen;
703	char	       *fname,*aname;
704	u_int32_t       aoff;
705	struct ntnode  *nip;
706
707	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
708	if (error || (vap->va_flag & NTFS_AF_INRUN))
709		return (ENOTDIR);
710
711	blsize = vap->va_a_iroot->ir_size;
712	rdsize = vap->va_datalen;
713
714	fname = cnp->cn_nameptr;
715	aname = NULL;
716	anamelen = 0;
717	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
718		if(fname[fnamelen] == ':') {
719			aname = fname + fnamelen + 1;
720			anamelen = cnp->cn_namelen - fnamelen - 1;
721			dprintf(("ntfs_ntlookup: file %s (%d), attr: %s (%d)\n",
722				fname, fnamelen, aname, anamelen));
723			break;
724		}
725
726	dprintf(("ntfs_ntlookup: blocksize: %d, rdsize: %d\n", blsize, rdsize));
727
728	MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK);
729
730	error = ntfs_breadattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
731			       0, rdsize, rdbuf);
732	if (error)
733		goto fail;
734
735	aoff = sizeof(struct attr_indexroot);
736
737	do {
738		iep = (struct attr_indexentry *) (rdbuf + aoff);
739
740		while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) {
741			ddprintf(("scan: %d, %d\n",
742				  (u_int32_t) iep->ie_number,
743				  (u_int32_t) iep->ie_fnametype));
744			res = ntfs_uastricmp(ntmp, iep->ie_fname,
745					     iep->ie_fnamelen, fname,
746					     fnamelen);
747			if (res == 0) {
748				/* Matched something (case ins.) */
749				if (iep->ie_fnametype == 0 ||
750				    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
751					res = ntfs_uastrcmp(ntmp,
752							    iep->ie_fname,
753							    iep->ie_fnamelen,
754							    fname,
755							    fnamelen);
756				if (res == 0) {
757					error = ntfs_ntget(ntmp,
758							   iep->ie_number,
759							   &nip);
760					if(error)
761						goto fail;
762
763					nip->i_fflag = iep->ie_fflag;
764					nip->i_pnumber = iep->ie_fpnumber;
765					nip->i_times = iep->ie_ftimes;
766
767					if(nip->i_fflag & NTFS_FFLAG_DIR) {
768						nip->i_type = VDIR;
769						nip->i_defattr = 0;
770						nip->i_defattrname = NULL;
771					} else {
772						nip->i_type = VREG;
773						nip->i_defattr = NTFS_A_DATA;
774						nip->i_defattrname = NULL;
775					}
776					if (aname) {
777						error = ntfs_ntlookupattr(ntmp,
778							aname, anamelen,
779							&nip->i_defattr,
780							&nip->i_defattrname);
781						if (error) {
782							ntfs_ntrele(nip);
783							goto fail;
784						}
785
786						nip->i_type = VREG;
787
788						if (nip->i_defattrname)
789							nip->i_flag |= IN_AATTRNAME;
790					} else {
791						/* Opening default attribute */
792						nip->i_size = iep->ie_fsize;
793						nip->i_allocated =
794							iep->ie_fallocated;
795						nip->i_flag |= IN_PRELOADED;
796					}
797					*ipp = nip;
798					goto fail;
799				}
800			} else if (res > 0)
801				break;
802
803			aoff += iep->reclen;
804			iep = (struct attr_indexentry *) (rdbuf + aoff);
805		}
806
807		/* Dive if possible */
808		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
809			dprintf(("ntfs_ntlookup: diving\n"));
810
811			cn = *(cn_t *) (rdbuf + aoff +
812					iep->reclen - sizeof(cn_t));
813			rdsize = blsize;
814
815			error = ntfs_breadattr(ntmp, ip, NTFS_A_INDX, "$I30",
816					     ntfs_cntob(cn), rdsize, rdbuf);
817			if (error)
818				goto fail;
819
820			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
821						rdbuf, rdsize);
822			if (error)
823				goto fail;
824
825			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
826				0x18);
827		} else {
828			dprintf(("ntfs_ntlookup: nowhere to dive :-(\n"));
829			error = ENOENT;
830			break;
831		}
832	} while (1);
833
834	dprintf(("finish\n"));
835
836fail:
837	ntfs_ntvattrrele(vap);
838	FREE(rdbuf, M_TEMP);
839	return (error);
840}
841
842int
843ntfs_isnamepermitted(
844		     struct ntfsmount * ntmp,
845		     struct attr_indexentry * iep)
846{
847
848	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
849		return 1;
850
851	switch (iep->ie_fnametype) {
852	case 2:
853		ddprintf(("ntfs_isnamepermitted: skiped DOS name\n"));
854		return 0;
855	case 0:
856	case 1:
857	case 3:
858		return 1;
859	default:
860		printf("ntfs_isnamepermitted: " \
861		       "WARNING! Unknown file name type: %d\n",
862		       iep->ie_fnametype);
863		break;
864	}
865	return 0;
866}
867
868/*
869 * #undef dprintf #define dprintf(a) printf a
870 */
871int
872ntfs_ntreaddir(
873	       struct ntfsmount * ntmp,
874	       struct ntnode * ip,
875	       u_int32_t num,
876	       struct attr_indexentry ** riepp)
877{
878	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
879	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
880	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
881	caddr_t         rdbuf;		/* Buffer to read directory's blocks  */
882	u_char         *bmp = NULL;	/* Bitmap */
883	u_int32_t       blsize;		/* Index allocation size (2048) */
884	u_int32_t       rdsize;		/* Length of data to read */
885	u_int32_t       attrnum;	/* Current attribute type */
886	u_int32_t       cpbl = 1;	/* Clusters per directory block */
887	u_int32_t       blnum;
888	struct attr_indexentry *iep;
889	int             error = ENOENT;
890	u_int32_t       aoff, cnum;
891
892	dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
893	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
894	if (error)
895		return (ENOTDIR);
896
897	blsize = ip->i_dirblsz;
898	rdbuf = ip->i_dirblbuf;
899
900	dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize));
901
902	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
903		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
904					0, &bmvap);
905		if (error) {
906			error = ENOTDIR;
907			goto fail;
908		}
909		MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK);
910		error = ntfs_breadattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
911				       bmvap->va_datalen, bmp);
912		if (error)
913			goto fail;
914
915		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
916					0, &iavap);
917		if (error) {
918			error = ENOTDIR;
919			goto fail;
920		}
921		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
922		dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
923			 iavap->va_datalen, cpbl));
924	} else {
925		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
926		iavap = bmvap = NULL;
927		bmp = NULL;
928	}
929
930	/* Try use previous values */
931	if ((ip->i_lastdnum < num) && (ip->i_lastdnum != 0)) {
932		attrnum = ip->i_lastdattr;
933		aoff = ip->i_lastdoff;
934		blnum = ip->i_lastdblnum;
935		cnum = ip->i_lastdnum;
936	} else {
937		attrnum = NTFS_A_INDXROOT;
938		aoff = sizeof(struct attr_indexroot);
939		blnum = 0;
940		cnum = 0;
941	}
942
943	do {
944		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
945			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
946		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
947		error = ntfs_breadattr(ntmp, ip, attrnum, "$I30",
948				   ntfs_cntob(blnum * cpbl), rdsize, rdbuf);
949		if (error)
950			goto fail;
951
952		if (attrnum == NTFS_A_INDX) {
953			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
954						rdbuf, rdsize);
955			if (error)
956				goto fail;
957		}
958		if (aoff == 0)
959			aoff = (attrnum == NTFS_A_INDX) ?
960				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
961				sizeof(struct attr_indexroot);
962
963		iep = (struct attr_indexentry *) (rdbuf + aoff);
964		while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) {
965			if (ntfs_isnamepermitted(ntmp, iep)) {
966				if (cnum >= num) {
967					ip->i_lastdnum = cnum;
968					ip->i_lastdoff = aoff;
969					ip->i_lastdblnum = blnum;
970					ip->i_lastdattr = attrnum;
971
972					*riepp = iep;
973
974					error = 0;
975					goto fail;
976				}
977				cnum++;
978			}
979			aoff += iep->reclen;
980			iep = (struct attr_indexentry *) (rdbuf + aoff);
981		}
982
983		if (iavap) {
984			if (attrnum == NTFS_A_INDXROOT)
985				blnum = 0;
986			else
987				blnum++;
988
989			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
990				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
991					break;
992				blnum++;
993			}
994
995			attrnum = NTFS_A_INDX;
996			aoff = 0;
997			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
998				break;
999			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
1000		}
1001	} while (iavap);
1002
1003	*riepp = NULL;
1004	ip->i_lastdnum = 0;
1005
1006fail:
1007	if (vap)
1008		ntfs_ntvattrrele(vap);
1009	if (bmvap)
1010		ntfs_ntvattrrele(bmvap);
1011	if (iavap)
1012		ntfs_ntvattrrele(iavap);
1013	if (bmp)
1014		FREE(bmp, M_TEMP);
1015	return (error);
1016}
1017/*
1018 * #undef dprintf #define dprintf(a)
1019 */
1020
1021struct timespec
1022ntfs_nttimetounix(
1023		  u_int64_t nt)
1024{
1025	struct timespec t;
1026
1027	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
1028	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
1029	t.tv_sec = nt / (1000 * 1000 * 10) -
1030		369LL * 365LL * 24LL * 60LL * 60LL -
1031		89LL * 1LL * 24LL * 60LL * 60LL;
1032	return (t);
1033}
1034
1035int
1036ntfs_times(
1037	   struct ntfsmount * ntmp,
1038	   struct ntnode * ip,
1039	   ntfs_times_t * tm)
1040{
1041	struct ntvattr *vap;
1042	int             error;
1043
1044	dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
1045	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
1046	if (error)
1047		return (error);
1048	*tm = vap->va_a_name->n_times;
1049	ntfs_ntvattrrele(vap);
1050
1051	return (0);
1052}
1053
1054int
1055ntfs_filesize(
1056	      struct ntfsmount * ntmp,
1057	      struct ntnode * ip,
1058	      u_int64_t * size,
1059	      u_int64_t * bytes)
1060{
1061	struct ntvattr *vap;
1062	u_int64_t       sz, bn;
1063	int             error;
1064
1065	dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
1066	error = ntfs_ntvattrget(ntmp, ip, ip->i_defattr, ip->i_defattrname,
1067				0, &vap);
1068	if (error)
1069		return (error);
1070	bn = vap->va_allocated;
1071	sz = vap->va_datalen;
1072
1073	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
1074		(u_int32_t) sz, (u_int32_t) bn));
1075
1076	if (size)
1077		*size = sz;
1078	if (bytes)
1079		*bytes = bn;
1080
1081	ntfs_ntvattrrele(vap);
1082
1083	return (0);
1084}
1085
1086int
1087ntfs_breadntvattr_plain(
1088			struct ntfsmount * ntmp,
1089			struct ntnode * ip,
1090			struct ntvattr * vap,
1091			off_t roff,
1092			size_t rsize,
1093			void *rdata,
1094			size_t * initp)
1095{
1096	int             error = 0;
1097	int             off;
1098
1099	*initp = 0;
1100	if (vap->va_flag & NTFS_AF_INRUN) {
1101		int             cnt;
1102		cn_t            ccn, ccl, cn, left, cl;
1103		caddr_t         data = rdata;
1104		struct buf     *bp;
1105		size_t          tocopy;
1106
1107		ddprintf(("ntfs_breadntvattr_plain: data in run: %d chains\n",
1108			 vap->va_vruncnt));
1109
1110		off = roff;
1111		left = rsize;
1112		ccl = 0;
1113		ccn = 0;
1114		cnt = 0;
1115		while (left && (cnt < vap->va_vruncnt)) {
1116			ccn = vap->va_vruncn[cnt];
1117			ccl = vap->va_vruncl[cnt];
1118
1119			ddprintf(("ntfs_breadntvattr_plain: " \
1120				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1121				 (u_int32_t) left, (u_int32_t) ccn, \
1122				 (u_int32_t) ccl, (u_int32_t) off));
1123
1124			if (ntfs_cntob(ccl) < off) {
1125				off -= ntfs_cntob(ccl);
1126				cnt++;
1127				continue;
1128			}
1129			if (ccn || ip->i_number == NTFS_BOOTINO) { /* XXX */
1130				ccl -= ntfs_btocn(off);
1131				cn = ccn + ntfs_btocn(off);
1132				off = ntfs_btocnoff(off);
1133
1134				while (left && ccl) {
1135					tocopy = min(left,
1136						  min(ntfs_cntob(ccl) - off,
1137						      MAXBSIZE - off));
1138					cl = ntfs_btocl(tocopy + off);
1139					ddprintf(("ntfs_breadntvattr_plain: " \
1140						"read: cn: 0x%x cl: %d, " \
1141						"off: %d len: %d, left: %d\n",
1142						(u_int32_t) cn,
1143						(u_int32_t) cl,
1144						(u_int32_t) off,
1145						(u_int32_t) tocopy,
1146						(u_int32_t) left));
1147					error = bread(ntmp->ntm_devvp,
1148						      ntfs_cntobn(cn),
1149						      ntfs_cntob(cl),
1150						      NOCRED, &bp);
1151					if (error) {
1152						brelse(bp);
1153						return (error);
1154					}
1155					memcpy(data, bp->b_data + off, tocopy);
1156					brelse(bp);
1157					data = data + tocopy;
1158					*initp += tocopy;
1159					off = 0;
1160					left -= tocopy;
1161					cn += cl;
1162					ccl -= cl;
1163				}
1164			} else {
1165				tocopy = min(left, ntfs_cntob(ccl) - off);
1166				ddprintf(("ntfs_breadntvattr_plain: "
1167					"sparce: ccn: 0x%x ccl: %d, off: %d, " \
1168					" len: %d, left: %d\n",
1169					(u_int32_t) ccn, (u_int32_t) ccl,
1170					(u_int32_t) off, (u_int32_t) tocopy,
1171					(u_int32_t) left));
1172				left -= tocopy;
1173				off = 0;
1174				bzero(data, tocopy);
1175				data = data + tocopy;
1176			}
1177			cnt++;
1178		}
1179		if (left) {
1180			printf("ntfs_breadntvattr_plain: POSSIBLE RUN ERROR\n");
1181			error = E2BIG;
1182		}
1183	} else {
1184		ddprintf(("ntfs_breadnvattr_plain: data is in mft record\n"));
1185		memcpy(rdata, vap->va_datap + roff, rsize);
1186		*initp += rsize;
1187	}
1188
1189	return (error);
1190}
1191
1192int
1193ntfs_breadattr_plain(
1194		     struct ntfsmount * ntmp,
1195		     struct ntnode * ip,
1196		     u_int32_t attrnum,
1197		     char *attrname,
1198		     off_t roff,
1199		     size_t rsize,
1200		     void *rdata,
1201		     size_t * initp)
1202{
1203	size_t          init;
1204	int             error = 0;
1205	off_t           off = roff, left = rsize, toread;
1206	caddr_t         data = rdata;
1207	struct ntvattr *vap;
1208	*initp = 0;
1209
1210	while (left) {
1211		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1212					ntfs_btocn(off), &vap);
1213		if (error)
1214			return (error);
1215		toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1216		ddprintf(("ntfs_breadattr_plain: o: %d, s: %d (%d - %d)\n",
1217			 (u_int32_t) off, (u_int32_t) toread,
1218			 (u_int32_t) vap->va_vcnstart,
1219			 (u_int32_t) vap->va_vcnend));
1220		error = ntfs_breadntvattr_plain(ntmp, ip, vap,
1221					 off - ntfs_cntob(vap->va_vcnstart),
1222					 toread, data, &init);
1223		if (error) {
1224			printf("ntfs_breadattr_plain: " \
1225			       "ntfs_breadntvattr_plain failed: o: %d, s: %d\n",
1226			       (u_int32_t) off, (u_int32_t) toread);
1227			printf("ntfs_breadattr_plain: attrib: %d - %d\n",
1228			       (u_int32_t) vap->va_vcnstart,
1229			       (u_int32_t) vap->va_vcnend);
1230			ntfs_ntvattrrele(vap);
1231			break;
1232		}
1233		ntfs_ntvattrrele(vap);
1234		left -= toread;
1235		off += toread;
1236		data = data + toread;
1237		*initp += init;
1238	}
1239
1240	return (error);
1241}
1242
1243int
1244ntfs_breadattr(
1245	       struct ntfsmount * ntmp,
1246	       struct ntnode * ip,
1247	       u_int32_t attrnum,
1248	       char *attrname,
1249	       off_t roff,
1250	       size_t rsize,
1251	       void *rdata)
1252{
1253	int             error = 0;
1254	struct ntvattr *vap;
1255	size_t          init;
1256
1257	ddprintf(("ntfs_breadattr: reading %d: 0x%x, from %d size %d bytes\n",
1258	       ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
1259
1260	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
1261	if (error)
1262		return (error);
1263
1264	if ((roff > vap->va_datalen) ||
1265	    (roff + rsize > vap->va_datalen)) {
1266		ddprintf(("ntfs_breadattr: offset too big\n"));
1267		ntfs_ntvattrrele(vap);
1268		return (E2BIG);
1269	}
1270	if (vap->va_compression && vap->va_compressalg) {
1271		u_int8_t       *cup;
1272		u_int8_t       *uup;
1273		off_t           off = roff, left = rsize, tocopy;
1274		caddr_t         data = rdata;
1275		cn_t            cn;
1276
1277		ddprintf(("ntfs_ntreadattr: compression: %d\n",
1278			 vap->va_compressalg));
1279
1280		MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1281		       M_NTFSDECOMP, M_WAITOK);
1282		MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1283		       M_NTFSDECOMP, M_WAITOK);
1284
1285		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
1286		off = roff - ntfs_cntob(cn);
1287
1288		while (left) {
1289			error = ntfs_breadattr_plain(ntmp, ip, attrnum,
1290						  attrname, ntfs_cntob(cn),
1291					          ntfs_cntob(NTFS_COMPUNIT_CL),
1292						  cup, &init);
1293			if (error)
1294				break;
1295
1296			tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
1297
1298			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
1299				memcpy(data, cup + off, tocopy);
1300			} else if (init == 0) {
1301				bzero(data, tocopy);
1302			} else {
1303				error = ntfs_uncompunit(ntmp, uup, cup);
1304				if (error)
1305					break;
1306				memcpy(data, uup + off, tocopy);
1307			}
1308
1309			left -= tocopy;
1310			data = data + tocopy;
1311			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
1312			cn += NTFS_COMPUNIT_CL;
1313		}
1314
1315		FREE(uup, M_NTFSDECOMP);
1316		FREE(cup, M_NTFSDECOMP);
1317	} else
1318		error = ntfs_breadattr_plain(ntmp, ip, attrnum, attrname,
1319					     roff, rsize, rdata, &init);
1320	ntfs_ntvattrrele(vap);
1321	return (error);
1322}
1323
1324int
1325ntfs_parserun(
1326	      cn_t * cn,
1327	      cn_t * cl,
1328	      u_int8_t * run,
1329	      size_t len,
1330	      int *off)
1331{
1332	u_int8_t        sz;
1333	int             i;
1334
1335	if (NULL == run) {
1336		printf("ntfs_runtocn: run == NULL\n");
1337		return (EINVAL);
1338	}
1339	sz = run[(*off)++];
1340	if (0 == sz) {
1341		printf("ntfs_parserun: trying to go out of run\n");
1342		return (E2BIG);
1343	}
1344	*cl = 0;
1345	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1346		printf("ntfs_parserun: " \
1347		       "bad run: length too big: %02x (%x < %x + sz)\n",
1348		       sz, len, *off);
1349		return (EINVAL);
1350	}
1351	for (i = 0; i < (sz & 0xF); i++)
1352		*cl += (u_int32_t) run[(*off)++] << (i << 3);
1353
1354	sz >>= 4;
1355	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1356		printf("ntfs_parserun: " \
1357		       "bad run: offset too big: %02x (%x < %x + sz)\n",
1358		       sz, len, *off);
1359		return (EINVAL);
1360	}
1361	for (i = 0; i < (sz & 0xF); i++)
1362		*cn += (u_int32_t) run[(*off)++] << (i << 3);
1363
1364	return (0);
1365}
1366
1367int
1368ntfs_procfixups(
1369		struct ntfsmount * ntmp,
1370		u_int32_t magic,
1371		caddr_t buf,
1372		size_t len)
1373{
1374	struct fixuphdr *fhp = (struct fixuphdr *) buf;
1375	int             i;
1376	u_int16_t       fixup;
1377	u_int16_t      *fxp;
1378	u_int16_t      *cfxp;
1379
1380	if (fhp->fh_magic != magic) {
1381		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
1382		       fhp->fh_magic, magic);
1383		return (EINVAL);
1384	}
1385	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1386		printf("ntfs_procfixups: " \
1387		       "bad fixups number: %d for %d bytes block\n",
1388		       fhp->fh_fnum, len);
1389		return (EINVAL);
1390	}
1391	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1392		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
1393		return (EINVAL);
1394	}
1395	fxp = (u_int16_t *) (buf + fhp->fh_foff);
1396	cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
1397	fixup = *fxp++;
1398	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
1399		if (*cfxp != fixup) {
1400			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
1401			return (EINVAL);
1402		}
1403		*cfxp = *fxp;
1404		((caddr_t) cfxp) += ntmp->ntm_bps;
1405	}
1406	return (0);
1407}
1408
1409int
1410ntfs_runtocn(
1411	     cn_t * cn,
1412	     struct ntfsmount * ntmp,
1413	     u_int8_t * run,
1414	     size_t len,
1415	     cn_t vcn)
1416{
1417	cn_t            ccn = 0;
1418	cn_t            ccl = 0;
1419	int             off = 0;
1420	int             error = 0;
1421
1422#if NTFS_DEBUG
1423	int             i;
1424	printf("ntfs_runtocn: " \
1425	       "run: 0x%p, %d bytes, vcn:%d\n", run, len, (u_int32_t) vcn);
1426	printf("ntfs_runtocn: run: ");
1427	for (i = 0; i < len; i++)
1428		printf("0x%02x ", run[i]);
1429	printf("\n");
1430#endif
1431
1432	if (NULL == run) {
1433		printf("ntfs_runtocn: run == NULL\n");
1434		return (EINVAL);
1435	}
1436	do {
1437		if (run[off] == 0) {
1438			printf("ntfs_runtocn: vcn too big\n");
1439			return (E2BIG);
1440		}
1441		vcn -= ccl;
1442		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
1443		if (error) {
1444			printf("ntfs_runtocn: ntfs_parserun failed\n");
1445			return (error);
1446		}
1447	} while (ccl <= vcn);
1448	*cn = ccn + vcn;
1449	return (0);
1450}
1451