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