]> code.delx.au - refind/blob - filesystems/fsw_ntfs.c
Fixed uninitialized-pointer bug that manifested as a crash with
[refind] / filesystems / fsw_ntfs.c
1 /**
2 * \file fsw_ntfs.c
3 * ntfs file system driver code.
4 * Copyright (C) 2015 by Samuel Liao
5 */
6
7 /*-
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 #include "fsw_core.h"
24
25 #define Print(x...) /* */
26
27 static inline fsw_u8 GETU8(fsw_u8 *buf, int pos)
28 {
29 return buf[pos];
30 }
31
32 static inline fsw_u16 GETU16(fsw_u8 *buf, int pos)
33 {
34 return fsw_u16_le_swap(*(fsw_u16 *)(buf+pos));
35 }
36
37 static inline fsw_u32 GETU32(fsw_u8 *buf, int pos)
38 {
39 return fsw_u32_le_swap(*(fsw_u32 *)(buf+pos));
40 }
41
42 static inline fsw_u64 GETU64(fsw_u8 *buf, int pos)
43 {
44 return fsw_u64_le_swap(*(fsw_u64 *)(buf+pos));
45 }
46
47 #define MFTMASK ((1ULL<<48) - 1)
48 #define BADMFT (~0ULL)
49 #define MFTNO_MFT 0
50 #define MFTNO_VOLUME 3
51 #define MFTNO_ROOT 5
52 #define MFTNO_UPCASE 10
53 #define MFTNO_META 16
54 #define BADVCN (~0ULL)
55
56 #define AT_STANDARD_INFORMATION 0x10
57 #define AT_ATTRIBUTE_LIST 0x20
58 #define AT_FILENAME 0x30 /* UNUSED */
59 #define AT_VOLUME_NAME 0x60
60 #define AT_VOLUME_INFORMATION 0x70 /* UNUSED */
61 #define AT_DATA 0x80
62 #define AT_INDEX_ROOT 0x90
63 #define AT_INDEX_ALLOCATION 0xa0
64 #define AT_BITMAP 0xb0
65 #define AT_REPARSE_POINT 0xc0
66
67 #define ATTRMASK 0xFFFF
68 #define ATTRBITS 16
69 /* $I30 is LE, we can't use L"$I30" */
70 #define NAME_I30 "$\0I\0003\0000\0"
71 #define AT_I30 0x40000
72
73 static const fsw_u16 upcase[0x80] =
74 {
75 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
76 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
77 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
78 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
79 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
80 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
81 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
82 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
83 };
84
85 struct extent_slot
86 {
87 fsw_u64 vcn;
88 fsw_u64 lcn;
89 fsw_u64 cnt;
90 };
91
92 struct extent_map
93 {
94 /*
95 * we build mft extent table instead use generic code, to prevent
96 * read_mft recursive or dead loop.
97 * While mft has too many fragments, it need AT_ATTRIBUTE_LIST for extra
98 * data, the AT_ATTRIBUTE_LIST parsing code need call read_mft again.
99 */
100 struct extent_slot *extent;
101 int total;
102 int used;
103 };
104
105 struct ntfs_mft
106 {
107 fsw_u64 mftno; /* current MFT no */
108 fsw_u8 *buf; /* current MFT record data */
109 fsw_u8 *atlst; /* AT_ATTRIBUTE_LIST data */
110 int atlen; /* AT_ATTRIBUTE_LIST size */
111 };
112
113 struct ntfs_attr
114 {
115 fsw_u64 emftno; /* MFT no of emft */
116 fsw_u8 *emft; /* cached extend MFT record */
117 fsw_u8 *ptr; /* current attribute data */
118 int len; /* current attribute size */
119 int type; /* current attribute type */
120 };
121
122 struct fsw_ntfs_volume
123 {
124 struct fsw_volume g;
125 struct extent_map extmap; /* MFT extent map */
126 fsw_u64 totalbytes; /* volume size */
127 const fsw_u16 *upcase; /* upcase map for non-ascii */
128 int upcount; /* upcase map size */
129
130 fsw_u8 sctbits; /* sector size */
131 fsw_u8 clbits; /* cluster size */
132 fsw_u8 mftbits; /* MFT record size */
133 fsw_u8 idxbits; /* unused index size, use AT_INDEX_ROOT instead */
134 };
135
136 struct fsw_ntfs_dnode
137 {
138 struct fsw_dnode g;
139 struct ntfs_mft mft;
140 struct ntfs_attr attr; /* AT_INDEX_ALLOCATION:$I30/AT_DATA */
141 fsw_u8 *idxroot; /* AT_INDEX_ROOT:$I30 */
142 fsw_u8 *idxbmp; /* AT_BITMAP:$I30 */
143 unsigned int embeded:1; /* embeded AT_DATA */
144 unsigned int has_idxtree:1; /* valid AT_INDEX_ALLOCATION:$I30 */
145 unsigned int compressed:1; /* compressed AT_DATA */
146 unsigned int unreadable:1; /* unreadable/encrypted AT_DATA */
147 unsigned int cpfull:1; /* in-compressable chunk */
148 unsigned int cpzero:1; /* empty chunk */
149 unsigned int cperror:1; /* decompress error */
150 unsigned int islink:1; /* is symlink: AT_REPARSE_POINT */
151 int idxsz; /* size of index block */
152 int rootsz; /* size of idxroot: AT_INDEX_ROOT:$I30 */
153 int bmpsz; /* size of idxbmp: AT_BITMAP:$I30 */
154 struct extent_slot cext; /* cached extent */
155 fsw_u64 fsize; /* logical file size */
156 fsw_u64 finited; /* initialized file size */
157 fsw_u64 cvcn; /* vcn of compress chunk: cbuf */
158 fsw_u64 clcn[16]; /* cluster map of compress chunk */
159 fsw_u8 *cbuf; /* compress chunk/index block/symlink target */
160 };
161
162 static fsw_status_t fixup(fsw_u8 *record, char *magic, int sectorsize, int size)
163 {
164 int off, cnt, i;
165 fsw_u16 val;
166
167 if(*(int *)record != *(int *)magic)
168 return FSW_VOLUME_CORRUPTED;
169
170 off = GETU16(record, 4);
171 cnt = GETU16(record, 6);
172 if(size && sectorsize*(cnt-1) != size)
173 return FSW_VOLUME_CORRUPTED;
174 val = GETU16(record, off);
175 for(i=1; i<cnt; i++) {
176 if(GETU16(record, i*sectorsize-2)!=val)
177 return FSW_VOLUME_CORRUPTED;
178
179 *(fsw_u16 *)(record+i*sectorsize-2) = *(fsw_u16 *)(record+off+i*2);
180 }
181 return FSW_SUCCESS;
182 }
183
184 /* only supported attribute name is $I30 */
185 static fsw_status_t find_attribute_direct(fsw_u8 *mft, int mftsize, int type, fsw_u8 **outptr, int *outlen)
186 {
187 int namelen;
188 fsw_u32 n;
189
190 if(GETU32(mft, 0x18) < mftsize)
191 mftsize = GETU32(mft, 0x18);
192 mftsize -= GETU16(mft, 0x14);
193 mft += GETU16(mft, 0x14);
194
195 namelen = type>>ATTRBITS;
196 type &= ATTRMASK;
197
198 for(n = 0; mftsize >= 8; mft += n, mftsize -= n) {
199 int t = GETU32(mft, 0);
200 n = GETU32(mft, 4);
201 if( t==0 || (t+1)==0 || t==0xffff || n<24 || mftsize<n)
202 break;
203
204 fsw_u8 ns = GETU8(mft, 9);
205 fsw_u8 *nm = mft + GETU8(mft, 10);
206 if(type==t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) {
207 if(outptr) *outptr = mft;
208 if(outlen) *outlen = n;
209 return FSW_SUCCESS;
210 }
211 }
212 return FSW_NOT_FOUND;
213 }
214
215 /* only supported attribute name is $I30 */
216 static fsw_status_t find_attrlist_direct(fsw_u8 *atlst, int atlen, int type, fsw_u64 vcn, fsw_u64 *out, int *pos)
217 {
218 fsw_u64 mftno = BADMFT;
219 int namelen;
220
221 namelen = type>>ATTRBITS;
222 type &= ATTRMASK;
223
224 while( *pos + 0x18 <= atlen) {
225 int off = *pos;
226 fsw_u32 t = GETU32(atlst, off);
227 fsw_u32 n = GETU16(atlst, off+4);
228
229 *pos = off + n;
230 if(t==0 || (t+1)==0 || t==0xffff || n < 0x18 || *pos > atlen)
231 break;
232
233 fsw_u8 ns = GETU8(atlst, off+6);
234 fsw_u8 *nm = atlst + off + GETU8(atlst, off+7);
235 if( type == t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) {
236 fsw_u64 avcn = GETU64(atlst, off+8);
237 if(vcn < avcn) {
238 if(mftno == BADMFT)
239 return FSW_NOT_FOUND;
240 *out = mftno;
241 return FSW_SUCCESS;
242 }
243 if(vcn == avcn) {
244 *out = GETU64(atlst, off+0x10) & MFTMASK;
245 return FSW_SUCCESS;
246 }
247 mftno = GETU64(atlst, off+0x10) & MFTMASK;
248 }
249 }
250 return FSW_NOT_FOUND;
251 }
252
253 static fsw_status_t get_extent(fsw_u8 **rlep, int *rlenp, fsw_u64 *lcnp, fsw_u64 *lenp, fsw_u64 *pos)
254 {
255 fsw_u8 *rle = *rlep;
256 fsw_u8 *rle_end = rle + *rlenp;
257 int f = *rle++;
258 fsw_u64 m = 1;
259 fsw_u64 c = 0;
260 fsw_u64 v = 0;
261
262 int n = f & 0xf;
263 if(n==0) return FSW_NOT_FOUND;
264
265 if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED;
266
267 while(--n >= 0) {
268 c += m * (*rle++);
269 m <<= 8;
270 }
271
272 n = f >> 4;
273 if(n==0) {
274 /* LCN 0 as sparse, due to we don't need $Boot */
275 *lcnp = 0;
276 *lenp = c;
277 } else {
278 if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED;
279
280 m = 1;
281 while(--n >= 0) {
282 v += m * (*rle++);
283 m <<= 8;
284 }
285
286 *pos += v;
287 if(v & (m>>1))
288 *pos -= m;
289
290 *lcnp = *pos;
291 *lenp = c;
292 }
293 *rlenp -= rle - *rlep;
294 *rlep = rle;
295 return FSW_SUCCESS;
296 }
297
298 static inline int attribute_ondisk(fsw_u8 *ptr, int len)
299 {
300 return GETU8(ptr, 8);
301 }
302
303 static inline int attribute_compressed(fsw_u8 *ptr, int len)
304 {
305 return (GETU8(ptr, 12) & 0xFF) == 1;
306 }
307
308 static inline int attribute_compressed_future(fsw_u8 *ptr, int len)
309 {
310 return (GETU8(ptr, 12) & 0xFF) > 1;
311 }
312
313 static inline int attribute_sparse(fsw_u8 *ptr, int len)
314 {
315 return GETU8(ptr, 12) & 0x8000;
316 }
317
318 static inline int attribute_encrypted(fsw_u8 *ptr, int len)
319 {
320 return GETU8(ptr, 12) & 0x4000;
321 }
322
323 static void attribute_get_embeded(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp)
324 {
325 int off = GETU16(ptr, 0x14);
326 int olen = GETU16(ptr, 0x10);
327 if(olen + off > len)
328 olen = len - off;
329 *outp = ptr + off;
330 *outlenp = olen;
331 }
332
333 static void attribute_get_rle(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp)
334 {
335 int off = GETU16(ptr, 0x20);
336 int olen = len - off;
337 *outp = ptr + off;
338 *outlenp = olen;
339 }
340
341 static inline int attribute_rle_offset(fsw_u8 *ptr, int len)
342 {
343 return GETU16(ptr, 0x20);
344 }
345
346 static inline fsw_u64 attribute_size(fsw_u8 *ptr, int len)
347 {
348 return GETU8(ptr, 8) ? GETU64(ptr, 0x30) : GETU16(ptr, 0x10);
349 }
350
351 static inline fsw_u64 attribute_inited_size(fsw_u8 *ptr, int len)
352 {
353 return GETU8(ptr, 8) ? GETU64(ptr, 0x38) : GETU16(ptr, 0x10);
354 }
355
356 static inline int attribute_has_vcn(fsw_u8 *ptr, int len, fsw_u64 vcn) {
357 if(GETU8(ptr, 8)==0)
358 return 1;
359 return vcn >= GETU64(ptr, 0x10) && vcn <= GETU64(ptr, 0x18);
360 }
361
362 static inline fsw_u64 attribute_first_vcn(fsw_u8 *ptr, int len)
363 {
364 return GETU8(ptr, 8) ? GETU64(ptr, 0x10) : 0;
365 }
366
367 static inline fsw_u64 attribute_last_vcn(fsw_u8 *ptr, int len)
368 {
369 return GETU8(ptr, 8) ? GETU64(ptr, 0x18) : 0;
370 }
371
372 static fsw_status_t read_attribute_direct(struct fsw_ntfs_volume *vol, fsw_u8 *ptr, int len, fsw_u8 **optrp, int *olenp)
373 {
374 fsw_status_t err;
375 int olen;
376
377 if(attribute_ondisk(ptr, len) == 0) {
378 /* EMBEDED DATA */
379 attribute_get_embeded(ptr, len, &ptr, &len);
380 *olenp = len;
381 if(optrp) {
382 if((err = fsw_alloc(len, (void **)optrp)) != FSW_SUCCESS)
383 return err;
384 fsw_memcpy(*optrp, ptr, len);
385 }
386 return FSW_SUCCESS;
387 }
388
389 olen = attribute_size(ptr, len);
390 *olenp = olen;
391 if(!optrp)
392 return FSW_SUCCESS;
393
394 if((err = fsw_alloc_zero(olen, (void **)optrp)) != FSW_SUCCESS)
395 return err;
396 fsw_u8 *buf = *optrp;
397
398 attribute_get_rle(ptr, len, &ptr, &len);
399
400 fsw_u64 pos = 0;
401 int clustersize = 1<<vol->clbits;
402 fsw_u64 lcn, cnt;
403
404 while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
405 if(lcn) {
406 for(; cnt>0; lcn++, cnt--) {
407 fsw_u8 *block;
408 if (fsw_block_get(&vol->g, lcn, 0, (void **)&block) != FSW_SUCCESS)
409 {
410 fsw_free(*optrp);
411 *optrp = NULL;
412 *olenp = 0;
413 return FSW_VOLUME_CORRUPTED;
414 }
415 fsw_memcpy(buf, block, clustersize > olen ? olen : clustersize);
416 fsw_block_release(&vol->g, lcn, block);
417
418 buf += clustersize;
419 olen -= clustersize;
420 }
421 } else {
422 buf += cnt << vol->clbits;
423 olen -= cnt << vol->clbits;
424 }
425 }
426 return FSW_SUCCESS;
427 }
428
429 static void init_mft(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, fsw_u64 mftno)
430 {
431 mft->mftno = mftno;
432 mft->atlst = NULL;
433 mft->atlen = fsw_alloc(1<<vol->mftbits, &mft->buf);
434 mft->atlen = 0;
435 }
436
437 static void free_mft(struct ntfs_mft *mft)
438 {
439 if(mft->buf) fsw_free(mft->buf);
440 if(mft->atlst) fsw_free(mft->atlst);
441 }
442
443 static fsw_status_t load_atlist(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft)
444 {
445 fsw_u8 *ptr;
446 int len;
447 fsw_status_t err = find_attribute_direct(mft->buf, 1<<vol->mftbits, AT_ATTRIBUTE_LIST, &ptr, &len);
448 if(err != FSW_SUCCESS)
449 return err;
450 return read_attribute_direct(vol, ptr, len, &mft->atlst, &mft->atlen);
451 }
452
453 static fsw_status_t read_mft(struct fsw_ntfs_volume *vol, fsw_u8 *mft, fsw_u64 mftno)
454 {
455 int l = 0;
456 int r = vol->extmap.used - 1;
457 int m;
458 fsw_u64 vcn = (mftno << vol->mftbits) >> vol->clbits;
459 struct extent_slot *e = vol->extmap.extent;
460
461 while(l <= r) {
462 m = (l+r)/2;
463 if(vcn < e[m].vcn) {
464 r = m - 1;
465 } else if(vcn >= e[m].vcn + e[m].cnt) {
466 l = m + 1;
467 } else if(vol->mftbits <= vol->clbits) {
468 fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn);
469 int offset = (mftno << vol->mftbits) & ((1<<vol->clbits)-1);
470 fsw_u8 *buffer;
471 fsw_status_t err;
472
473 if(e[m].lcn + 1 == 0)
474 return FSW_VOLUME_CORRUPTED;
475
476 if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
477 return FSW_VOLUME_CORRUPTED;
478
479 fsw_memcpy(mft, buffer+offset, 1<<vol->mftbits);
480 fsw_block_release(&vol->g, lcn, buffer);
481 return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits);
482 } else {
483 fsw_u8 *p = mft;
484 fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn);
485 fsw_u64 ecnt = e[m].cnt - (vcn - e[m].vcn);
486 int count = 1 << (vol->mftbits - vol->clbits);
487 fsw_status_t err;
488
489 if(e[m].lcn + 1 == 0)
490 return FSW_VOLUME_CORRUPTED;
491 while(count-- > 0) {
492 fsw_u8 *buffer;
493 if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
494 return FSW_VOLUME_CORRUPTED;
495 fsw_memcpy(p, buffer, 1<<vol->clbits);
496 fsw_block_release(&vol->g, lcn, buffer);
497
498 p += 1<<vol->clbits;
499 ecnt--;
500 vcn++;
501 if(count==0) break;
502 if(ecnt > 0) {
503 lcn++;
504 } else if(++m >= vol->extmap.used || e[m].vcn != vcn) {
505 return FSW_VOLUME_CORRUPTED;
506 } else {
507 lcn = e[m].lcn;
508 ecnt = e[m].cnt;
509 }
510 }
511 return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits);
512 }
513 }
514 return FSW_NOT_FOUND;
515 }
516
517 static void init_attr(struct fsw_ntfs_volume *vol, struct ntfs_attr *attr, int type)
518 {
519 fsw_memzero(attr, sizeof(*attr));
520 attr->type = type;
521 attr->emftno = BADMFT;
522 }
523
524 static void free_attr(struct ntfs_attr *attr)
525 {
526 if(attr->emft) fsw_free(attr->emft);
527 }
528
529 static fsw_status_t find_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, struct ntfs_attr *attr, fsw_u64 vcn)
530 {
531 fsw_u8 *buf = mft->buf;
532 if(mft->atlst && mft->atlen) {
533 fsw_status_t err;
534 fsw_u64 mftno;
535 int pos = 0;
536
537 err = find_attrlist_direct(mft->atlst, mft->atlen, attr->type, vcn, &mftno, &pos);
538 if(err != FSW_SUCCESS)
539 return err;
540
541 if(mftno == mft->mftno) {
542 buf = mft->buf;
543 } else if(mftno == attr->emftno && attr->emft) {
544 buf = attr->emft;
545 } else {
546 attr->emftno = BADMFT;
547 err = fsw_alloc(1<<vol->mftbits, &attr->emft);
548 if(err != FSW_SUCCESS)
549 return err;
550 err = read_mft(vol, attr->emft, mftno);
551 if(err != FSW_SUCCESS)
552 return err;
553 attr->emftno = mftno;
554 buf = attr->emft;
555 }
556 }
557 return find_attribute_direct(buf, 1<<vol->mftbits, attr->type, &attr->ptr, &attr->len);
558 }
559
560 static fsw_status_t read_small_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, int type, fsw_u8 **optrp, int *olenp)
561 {
562 fsw_status_t err;
563 struct ntfs_attr attr;
564
565 init_attr(vol, &attr, type);
566 err = find_attribute(vol, mft, &attr, 0);
567 if(err == FSW_SUCCESS)
568 err = read_attribute_direct(vol, attr.ptr, attr.len, optrp, olenp);
569 free_attr(&attr);
570 return err;
571 }
572
573 static void add_single_mft_map(struct fsw_ntfs_volume *vol, fsw_u8 *mft)
574 {
575 fsw_u8 *ptr;
576 int len;
577
578 if(find_attribute_direct(mft, 1<<vol->mftbits, AT_DATA, &ptr, &len)!=FSW_SUCCESS)
579 return;
580
581 if(attribute_ondisk(ptr, len) == 0)
582 return;
583
584 fsw_u64 vcn = GETU64(ptr, 0x10);
585 int off = GETU16(ptr, 0x20);
586 ptr += off;
587 len -= off;
588
589 fsw_u64 pos = 0;
590 fsw_u64 lcn, cnt;
591
592 while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
593 if(lcn) {
594 int u = vol->extmap.used;
595 if(u >= vol->extmap.total) {
596 vol->extmap.total = vol->extmap.extent ? u*2 : 16;
597 struct extent_slot *e;
598 if(fsw_alloc(vol->extmap.total * sizeof(struct extent_slot), &e)!=FSW_SUCCESS)
599 break;
600 if(vol->extmap.extent) {
601 fsw_memcpy(e, vol->extmap.extent, u*sizeof(struct extent_slot));
602 fsw_free(vol->extmap.extent);
603 }
604 vol->extmap.extent = e;
605 }
606 vol->extmap.extent[u].vcn = vcn;
607 vol->extmap.extent[u].lcn = lcn;
608 vol->extmap.extent[u].cnt = cnt;
609 vol->extmap.used++;
610 }
611 vcn += cnt;
612 }
613 }
614
615 static void add_mft_map(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft)
616 {
617 load_atlist(vol, mft);
618 add_single_mft_map(vol, mft->buf);
619 if(mft->atlst == NULL) return;
620
621 fsw_u64 mftno;
622 int pos = 0;
623
624 fsw_u8 *emft;
625 if(fsw_alloc(1<<vol->mftbits, &emft) != FSW_SUCCESS) return;
626 while(find_attrlist_direct(mft->atlst, mft->atlen, AT_DATA, 0, &mftno, &pos) == FSW_SUCCESS) {
627 if(mftno == 0) continue;
628 if(read_mft(vol, emft, mftno)==FSW_SUCCESS)
629 add_single_mft_map(vol, emft);
630 }
631 fsw_free(emft);
632 }
633
634 static int tobits(fsw_u32 val)
635 {
636 return 31 - __builtin_clz(val);
637 }
638
639 static fsw_status_t fsw_ntfs_volume_mount(struct fsw_volume *volg)
640 {
641 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
642 fsw_status_t err;
643 fsw_u8 *buffer;
644 int sector_size;
645 int cluster_size;
646 signed char tmp;
647 fsw_u64 mft_start[2];
648 struct ntfs_mft mft0;
649
650 fsw_set_blocksize(volg, 512, 512);
651 if ((err = fsw_block_get(volg, 0, 0, (void **)&buffer)) != FSW_SUCCESS)
652 return FSW_UNSUPPORTED;
653
654 if (!fsw_memeq(buffer+3, "NTFS ", 8))
655 return FSW_UNSUPPORTED;
656
657 sector_size = GETU16(buffer, 0xB);
658 if(sector_size==0 || (sector_size & (sector_size-1)) || sector_size < 0x100 || sector_size > 0x1000)
659 return FSW_UNSUPPORTED;
660
661 vol->sctbits = tobits(sector_size);
662 vol->totalbytes = GETU64(buffer, 0x28) << vol->sctbits;
663 Print(L"NTFS size=%ld M\n", vol->totalbytes>>20);
664
665 cluster_size = GETU8(buffer, 0xD) * sector_size;
666 if(cluster_size==0 || (cluster_size & (cluster_size-1)) || cluster_size > 0x10000)
667 return FSW_UNSUPPORTED;
668
669 vol->clbits = tobits(cluster_size);
670
671 tmp = GETU8(buffer, 0x40);
672 if(tmp > 0)
673 vol->mftbits = vol->clbits + tobits(tmp);
674 else
675 vol->mftbits = -tmp;
676
677 if(vol->mftbits < vol->sctbits || vol->mftbits > 16)
678 return FSW_UNSUPPORTED;
679
680 tmp = GETU8(buffer, 0x44);
681 if(tmp > 0)
682 vol->idxbits = vol->clbits + tobits(tmp);
683 else
684 vol->idxbits = -tmp;
685
686 if(vol->idxbits < vol->sctbits || vol->idxbits > 16)
687 return FSW_UNSUPPORTED;
688
689 mft_start[0] = GETU64(buffer, 0x30);
690 mft_start[1] = GETU64(buffer, 0x38);
691
692 fsw_block_release(volg, 0, (void *)buffer);
693 fsw_set_blocksize(volg, cluster_size, cluster_size);
694
695 init_mft(vol, &mft0, MFTNO_MFT);
696 for(tmp=0; tmp<2; tmp++) {
697 fsw_u8 *ptr = mft0.buf;
698 int len = 1 << vol->mftbits;
699 fsw_u64 lcn = mft_start[tmp];
700 while(len > 0) {
701 if ((err = fsw_block_get(volg, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
702 {
703 free_mft(&mft0);
704 return FSW_UNSUPPORTED;
705 }
706 int n = vol->mftbits < vol->clbits ? (1<<vol->mftbits) : cluster_size;
707 fsw_memcpy(ptr, buffer, n);
708 fsw_block_release(volg, lcn, (void *)buffer);
709 ptr += n;
710 len -= n;
711 lcn++;
712 }
713 err = fixup(mft0.buf, "FILE", sector_size, 1<<vol->mftbits);
714 if(err != FSW_SUCCESS)
715 return err;
716 }
717
718 add_mft_map(vol, &mft0);
719
720 {
721 int i;
722 for(i=0; i<vol->extmap.used; i++)
723 Print(L"extent %d: vcn=%lx lcn=%lx len=%lx\n",
724 i,
725 vol->extmap.extent[i].vcn,
726 vol->extmap.extent[i].lcn,
727 vol->extmap.extent[i].cnt);
728 }
729
730 free_mft(&mft0);
731
732 /* load $Volume name */
733 init_mft(vol, &mft0, MFTNO_VOLUME);
734 fsw_u8 *ptr;
735 int len;
736 if(read_mft(vol, mft0.buf, MFTNO_VOLUME)==FSW_SUCCESS &&
737 find_attribute_direct(mft0.buf, 1<<vol->mftbits, AT_VOLUME_NAME, &ptr, &len)==FSW_SUCCESS &&
738 GETU8(ptr, 8)==0)
739 {
740 struct fsw_string s;
741 s.type = FSW_STRING_TYPE_UTF16_LE;
742 s.size = GETU16(ptr, 0x10);
743 s.len = s.size / 2;
744 s.data = ptr + GETU16(ptr, 0x14);
745 Print(L"Volume name [%.*ls]\n", s.len, s.data);
746 err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s);
747 }
748 free_mft(&mft0);
749
750 err = fsw_dnode_create_root(volg, MFTNO_ROOT, &volg->root);
751 if (err)
752 return err;
753
754 return FSW_SUCCESS;
755 }
756
757 static void fsw_ntfs_volume_free(struct fsw_volume *volg)
758 {
759 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
760 if(vol->extmap.extent)
761 fsw_free(vol->extmap.extent);
762 if(vol->upcase && vol->upcase != upcase)
763 fsw_free((void *)vol->upcase);
764 }
765
766 static fsw_status_t fsw_ntfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb)
767 {
768 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
769 sb->total_bytes = vol->totalbytes;
770 /* reading through cluster bitmap is too costly */
771 sb->free_bytes = 0;
772 return FSW_SUCCESS;
773 }
774
775 static void fsw_ntfs_dnode_free(struct fsw_volume *vol, struct fsw_dnode *dnog)
776 {
777 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
778 free_mft(&dno->mft);
779 free_attr(&dno->attr);
780 if(dno->idxroot)
781 fsw_free(dno->idxroot);
782 if(dno->idxbmp)
783 fsw_free(dno->idxbmp);
784 if(dno->cbuf)
785 fsw_free(dno->cbuf);
786 }
787
788 static fsw_status_t fsw_ntfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog)
789 {
790 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
791 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
792 fsw_status_t err;
793 int len;
794
795 if(dno->mft.buf != NULL)
796 return FSW_SUCCESS;
797
798 init_mft(vol, &dno->mft, dno->g.dnode_id);
799 err = read_mft(vol, dno->mft.buf, dno->g.dnode_id);
800 if(err != FSW_SUCCESS)
801 goto error_out;
802
803 len = GETU8(dno->mft.buf, 22);
804 if( (len & 1) == 0 ) {
805 err = FSW_NOT_FOUND;
806 goto error_out;
807 }
808
809 load_atlist(vol, &dno->mft);
810
811 if(read_small_attribute(vol, &dno->mft, AT_REPARSE_POINT, &dno->cbuf, &len)==FSW_SUCCESS) {
812 switch(GETU32(dno->cbuf, 0)) {
813 case 0xa0000003:
814 case 0xa000000c:
815 dno->g.size = len;
816 dno->g.type = FSW_DNODE_TYPE_SYMLINK;
817 dno->islink = 1;
818 dno->fsize = len;
819 return FSW_SUCCESS;
820 default:
821 fsw_free(dno->cbuf);
822 dno->cbuf = NULL;
823 };
824 }
825
826 if( (len & 2) ) {
827 dno->g.type = FSW_DNODE_TYPE_DIR;
828 /* $INDEX_ROOT:$I30 must present */
829 err = read_small_attribute(vol, &dno->mft, AT_INDEX_ROOT|AT_I30, &dno->idxroot, &dno->rootsz);
830 if(err != FSW_SUCCESS)
831 {
832 Print(L"dno_fill INDEX_ROOT:$I30 error %d\n", err);
833 goto error_out;
834 }
835
836 dno->idxsz = GETU32(dno->idxroot, 8);
837 if(dno->idxsz == 0)
838 dno->idxsz = 1<<vol->idxbits;
839
840 /* $Bitmap:$I30 is optional */
841 err = read_small_attribute(vol, &dno->mft, AT_BITMAP|AT_I30, &dno->idxbmp, &dno->bmpsz);
842 if(err != FSW_SUCCESS && err != FSW_NOT_FOUND)
843 {
844 Print(L"dno_fill $Bitmap:$I30 error %d\n", err);
845 goto error_out;
846 }
847
848 /* $INDEX_ALLOCATION:$I30 is optional */
849 init_attr(vol, &dno->attr, AT_INDEX_ALLOCATION|AT_I30);
850 err = find_attribute(vol, &dno->mft, &dno->attr, 0);
851 if(err == FSW_SUCCESS) {
852 dno->has_idxtree = 1;
853 dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len);
854 dno->finited = dno->fsize;
855 } else if(err != FSW_NOT_FOUND) {
856 Print(L"dno_fill $INDEX_ALLOCATION:$I30 error %d\n", err);
857 goto error_out;
858 }
859
860 } else {
861 dno->g.type = FSW_DNODE_TYPE_FILE;
862 init_attr(vol, &dno->attr, AT_DATA);
863 err = find_attribute(vol, &dno->mft, &dno->attr, 0);
864 if(err != FSW_SUCCESS)
865 {
866 Print(L"dno_fill AT_DATA error %d\n", err);
867 goto error_out;
868 }
869 dno->embeded = !attribute_ondisk(dno->attr.ptr, dno->attr.len);
870 dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len);
871 dno->finited = attribute_inited_size(dno->attr.ptr, dno->attr.len);
872 if(attribute_encrypted(dno->attr.ptr, dno->attr.len))
873 dno->unreadable = 1;
874 else if(attribute_compressed_future(dno->attr.ptr, dno->attr.len))
875 dno->unreadable = 1;
876 else if(attribute_compressed(dno->attr.ptr, dno->attr.len))
877 dno->compressed = 1;
878 dno->cvcn = BADVCN;
879 dno->g.size = dno->fsize;
880 }
881 return FSW_SUCCESS;
882 error_out:
883 fsw_ntfs_dnode_free(volg, dnog);
884 // clear tag for good dnode
885 dno->mft.buf = NULL;
886 return err;
887 }
888
889 static fsw_u32 get_ntfs_time(fsw_u8 *buf, int pos)
890 {
891 fsw_u64 t = GETU64(buf, pos);
892 t = FSW_U64_DIV(t, 10000000);
893 t -= 134774ULL * 86400;
894 return t;
895 }
896
897 static fsw_status_t fsw_ntfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb)
898 {
899 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
900 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
901 fsw_status_t err;
902 fsw_u16 attr;
903 fsw_u8 *ptr;
904 int len;
905
906 err = find_attribute_direct(dno->mft.buf, 1<<vol->mftbits, AT_STANDARD_INFORMATION, &ptr, &len);
907
908 if(err != FSW_SUCCESS || GETU8(ptr, 8))
909 return err;
910
911 ptr += GETU16(ptr, 0x14);
912 attr = GETU8(ptr, 0x20); /* only lower 8 of 32 bit is used */
913 #ifndef EFI_FILE_READ_ONLY
914 #define EFI_FILE_READ_ONLY 1
915 #define EFI_FILE_HIDDEN 2
916 #define EFI_FILE_SYSTEM 4
917 #define EFI_FILE_DIRECTORY 0x10
918 #define EFI_FILE_ARCHIVE 0x20
919 #endif
920 attr &= EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE;
921 /* add DIR again if symlink */
922 if(GETU8(dno->mft.buf, 22) & 2)
923 attr |= EFI_FILE_DIRECTORY;
924
925 fsw_store_attr_efi(sb, attr);
926 sb->used_bytes = dno->fsize;
927 fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, get_ntfs_time(ptr, 24));
928 fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, get_ntfs_time(ptr, 8));
929 fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, get_ntfs_time(ptr, 16));
930
931 return FSW_SUCCESS;
932 }
933
934 static fsw_status_t fsw_ntfs_dnode_get_lcn(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 vcn, fsw_u64 *lcnp)
935 {
936 fsw_status_t err;
937 if(vcn >= dno->cext.vcn && vcn < dno->cext.vcn+dno->cext.cnt) {
938 *lcnp = dno->cext.lcn + vcn - dno->cext.vcn;
939 return FSW_SUCCESS;
940 }
941 if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) {
942 err = find_attribute(vol, &dno->mft, &dno->attr, vcn);
943 if( err != FSW_SUCCESS )
944 return err;
945 if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn))
946 return FSW_VOLUME_CORRUPTED;
947 }
948 fsw_u8 *ptr = dno->attr.ptr;
949 int len = dno->attr.len;
950 fsw_u64 pos = 0;
951 fsw_u64 lcn, cnt;
952 fsw_u64 svcn = attribute_first_vcn(ptr, len);
953 fsw_u64 evcn = attribute_last_vcn(ptr, len) + 1;
954 int off = GETU16(ptr, 0x20);
955 ptr += off;
956 len -= off;
957 while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
958 if(vcn >= svcn && vcn < svcn+cnt) {
959 dno->cext.vcn = svcn;
960 dno->cext.lcn = lcn;
961 dno->cext.cnt = cnt;
962 if(lcn == 0)
963 return FSW_NOT_FOUND;
964 *lcnp = lcn + vcn - svcn;
965 return FSW_SUCCESS;
966 }
967 svcn += cnt;
968 if(svcn >= evcn)
969 break;
970 }
971 return FSW_NOT_FOUND;
972 }
973
974 static int fsw_ntfs_read_buffer(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u8 *buf, fsw_u64 offset, int size)
975 {
976 if(dno->embeded) {
977 fsw_u8 *ptr;
978 int len;
979 attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len);
980 if(offset >= len)
981 return 0;
982 ptr += offset;
983 len -= offset;
984 if(size > len)
985 size = len;
986 fsw_memcpy(buf, ptr, size);
987 return size;
988 }
989
990 if(!dno->attr.ptr || !dno->attr.len) {
991 Print(L"BAD--------: attr.ptr %p attr.len %x cleared\n", dno->attr.ptr, dno->attr.len);
992 if(find_attribute(vol, &dno->mft, &dno->attr, 0) != FSW_SUCCESS)
993 return 0;
994 }
995
996 if(offset >= dno->fsize)
997 return 0;
998 if(offset + size >= dno->fsize)
999 size = dno->fsize - offset;
1000
1001 if(offset >= dno->finited) {
1002 fsw_memzero(buf, size);
1003 return size;
1004 }
1005
1006 int ret = 0;
1007 int zsize = 0;
1008 if(offset + size >= dno->finited) {
1009 zsize = offset + size - dno->finited;
1010 size = dno->finited - offset;
1011 }
1012
1013 fsw_u64 vcn = offset >> vol->clbits;
1014 int boff = offset & ((1<<vol->clbits)-1);
1015 fsw_u64 lcn = 0;
1016
1017 while(size > 0) {
1018 fsw_u8 *block;
1019 fsw_status_t err;
1020 int bsz;
1021
1022 err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn, &lcn);
1023 if (err != FSW_SUCCESS) break;
1024
1025 err = fsw_block_get(&vol->g, lcn, 0, (void **)&block);
1026 if (err != FSW_SUCCESS) break;
1027
1028 bsz = (1<<vol->clbits) - boff;
1029 if(bsz > size)
1030 bsz = size;
1031
1032 fsw_memcpy(buf, block+boff, bsz);
1033 fsw_block_release(&vol->g, lcn, block);
1034
1035 ret += bsz;
1036 buf += bsz;
1037 size -= bsz;
1038 boff = 0;
1039 vcn++;
1040 }
1041 if(size==0 && zsize > 0) {
1042 fsw_memzero(buf, zsize);
1043 ret += zsize;
1044 }
1045 return ret;
1046 }
1047
1048 static fsw_status_t fsw_ntfs_get_extent_embeded(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
1049 {
1050 fsw_status_t err;
1051 if(extent->log_start > 0)
1052 return FSW_NOT_FOUND;
1053 extent->log_count = 1;
1054 err = fsw_alloc(1<<vol->clbits, &extent->buffer);
1055 if(err != FSW_SUCCESS) return err;
1056 fsw_u8 *ptr;
1057 int len;
1058 attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len);
1059 if(len > (1<<vol->clbits))
1060 len = 1<<vol->clbits;
1061 fsw_memcpy(extent->buffer, ptr, len);
1062 extent->type = FSW_EXTENT_TYPE_BUFFER;
1063 return FSW_SUCCESS;
1064 }
1065
1066 static int ntfs_decomp_1page(fsw_u8 *src, int slen, fsw_u8 *dst) {
1067 int soff = 0;
1068 int doff = 0;
1069 while(soff < slen) {
1070 int j;
1071 int tag = src[soff++];
1072 for(j = 0; j < 8 && soff < slen; j++) {
1073 if(tag & (1<<j)){
1074 int len;
1075 int back;
1076 int bits;
1077
1078 if(!doff || soff + 2 > slen)
1079 return -1;
1080 len = GETU16(src, soff); soff += 2;
1081 bits = __builtin_clz((doff-1)>>3)-19;
1082 back = (len >> bits) + 1;
1083 len = (len & ((1<<bits)-1)) + 3;
1084 if(doff < back || doff + len > 0x1000)
1085 return -1;
1086 while(len-- > 0) {
1087 dst[doff] = dst[doff-back];
1088 doff++;
1089 }
1090 } else {
1091 if(doff >= 0x1000)
1092 return -1;
1093 dst[doff++] = src[soff++];
1094 }
1095 }
1096 }
1097 return doff;
1098 }
1099
1100 static int ntfs_decomp(fsw_u8 *src, int slen, fsw_u8 *dst, int npage) {
1101 fsw_u8 *se = src + slen;
1102 fsw_u8 *de = dst + (npage<<12);
1103 int i;
1104 for(i=0; i<npage; i++) {
1105 fsw_u16 slen = GETU16(src, 0);
1106 int comp = slen & 0x8000;
1107 slen = (slen&0xfff)+1;
1108 src += 2;
1109
1110 if(src + slen > se || dst + 0x1000 > de)
1111 return -1;
1112
1113 if(!comp) {
1114 fsw_memcpy(dst, src, slen);
1115 if(slen < 0x1000)
1116 fsw_memzero(dst+slen, 0x1000-slen);
1117 } else if(slen == 1) {
1118 fsw_memzero(dst, 0x1000);
1119 } else {
1120 int dlen = ntfs_decomp_1page(src, slen, dst);
1121 if(dlen < 0)
1122 return -1;
1123 if(dlen < 0x1000)
1124 fsw_memzero(dst+dlen, 0x1000-dlen);
1125 }
1126 src += slen;
1127 dst += 0x1000;
1128 }
1129 return 0;
1130 }
1131
1132 static fsw_status_t fsw_ntfs_get_extent_compressed(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
1133 {
1134 if(vol->clbits > 16)
1135 return FSW_VOLUME_CORRUPTED;
1136
1137 if((extent->log_start << vol->clbits) > dno->fsize)
1138 return FSW_NOT_FOUND;
1139
1140 int i;
1141 fsw_u64 vcn = extent->log_start & ~15;
1142
1143 if(vcn == dno->cvcn)
1144 goto hit;
1145 dno->cvcn = vcn;
1146 dno->cperror = 0;
1147 dno->cpfull = 0;
1148 dno->cpzero = 0;
1149
1150 for(i=0; i<16; i++) {
1151 fsw_status_t err;
1152 err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn+i, &dno->clcn[i]);
1153 if(err == FSW_NOT_FOUND) {
1154 break;
1155 } else if(err != FSW_SUCCESS) {
1156 Print(L"BAD LCN\n");
1157 dno->cperror = 1;
1158 return FSW_VOLUME_CORRUPTED;
1159 }
1160 }
1161 if(i == 0)
1162 dno->cpzero = 1;
1163 else if(i==16)
1164 dno->cpfull = 1;
1165 else {
1166 fsw_status_t err;
1167 if(dno->cbuf == NULL) {
1168 err = fsw_alloc(16<<vol->clbits, &dno->cbuf);
1169 if(err != FSW_SUCCESS) {
1170 dno->cvcn = BADVCN;
1171 return err;
1172 }
1173 }
1174 fsw_u8 *src;
1175 err = fsw_alloc(i << vol->clbits, &src);
1176 if(err != FSW_SUCCESS) {
1177 dno->cvcn = BADVCN;
1178 return err;
1179 }
1180 int b;
1181 for(b=0; b<i; b++) {
1182 char *block;
1183 if (fsw_block_get(&vol->g, dno->clcn[b], 0, (void **)&block) != FSW_SUCCESS) {
1184 dno->cperror = 1;
1185 Print(L"Read ERROR at block %d\n", i);
1186 break;
1187 }
1188 fsw_memcpy(src+(b<<vol->clbits), block, 1<<vol->clbits);
1189 fsw_block_release(&vol->g, dno->clcn[b], block);
1190 }
1191
1192 if(dno->fsize >= ((vcn+16)<<vol->clbits))
1193 b = 16<<vol->clbits>>12;
1194 else
1195 b = (dno->fsize - (vcn << vol->clbits) + 0xfff)>>12;
1196 if(!dno->cperror && ntfs_decomp(src, i<<vol->clbits, dno->cbuf, b) < 0)
1197 dno->cperror = 1;
1198 fsw_free(src);
1199 }
1200 hit:
1201 if(dno->cperror)
1202 return FSW_VOLUME_CORRUPTED;
1203 i = extent->log_start - vcn;
1204 if(dno->cpfull) {
1205 fsw_u64 lcn = dno->clcn[i];
1206 extent->phys_start = lcn;
1207 extent->log_count = 1;
1208 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
1209 for(i++, lcn++; i<16 && lcn==dno->clcn[i]; i++, lcn++)
1210 extent->log_count++;
1211 } else if(dno->cpzero) {
1212 extent->log_count = 16 - i;
1213 extent->buffer = NULL;
1214 extent->type = FSW_EXTENT_TYPE_SPARSE;
1215 } else {
1216 extent->log_count = 1;
1217 fsw_status_t err = fsw_alloc(1<<vol->clbits, &extent->buffer);
1218 if(err != FSW_SUCCESS) return err;
1219 fsw_memcpy(extent->buffer, dno->cbuf + (i<<vol->clbits), 1<<vol->clbits);
1220 extent->type = FSW_EXTENT_TYPE_BUFFER;
1221 }
1222 return FSW_SUCCESS;
1223 }
1224
1225 static fsw_status_t fsw_ntfs_get_extent_sparse(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
1226 {
1227 fsw_status_t err;
1228
1229 if((extent->log_start << vol->clbits) > dno->fsize)
1230 return FSW_NOT_FOUND;
1231 if((extent->log_start << vol->clbits) > dno->finited)
1232 {
1233 extent->log_count = 1;
1234 extent->buffer = NULL;
1235 extent->type = FSW_EXTENT_TYPE_SPARSE;
1236 return FSW_SUCCESS;
1237 }
1238 fsw_u64 lcn;
1239 err = fsw_ntfs_dnode_get_lcn(vol, dno, extent->log_start, &lcn);
1240 if(err == FSW_NOT_FOUND) {
1241 extent->log_count = 1;
1242 extent->buffer = NULL;
1243 extent->type = FSW_EXTENT_TYPE_SPARSE;
1244 return FSW_SUCCESS;
1245 }
1246 if(err != FSW_SUCCESS)
1247 return err;
1248 extent->phys_start = lcn;
1249 extent->log_count = 1;
1250 if(extent->log_start >= dno->cext.vcn && extent->log_start < dno->cext.vcn+dno->cext.cnt)
1251 extent->log_count = dno->cext.cnt + extent->log_start - dno->cext.vcn;
1252 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
1253 return FSW_SUCCESS;
1254 }
1255
1256 static fsw_status_t fsw_ntfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_extent *extent)
1257 {
1258 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
1259 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1260
1261 if(dno->unreadable)
1262 return FSW_UNSUPPORTED;
1263 if(dno->embeded)
1264 return fsw_ntfs_get_extent_embeded(vol, dno, extent);
1265 if(dno->compressed)
1266 return fsw_ntfs_get_extent_compressed(vol, dno, extent);
1267 return fsw_ntfs_get_extent_sparse(vol, dno, extent);
1268 }
1269
1270 static fsw_status_t load_upcase(struct fsw_ntfs_volume *vol)
1271 {
1272 fsw_status_t err;
1273 struct ntfs_mft mft;
1274 init_mft(vol, &mft, MFTNO_UPCASE);
1275 err = read_mft(vol, mft.buf, MFTNO_UPCASE);
1276 if(err == FSW_SUCCESS) {
1277 if((err = read_small_attribute(vol, &mft, AT_DATA, (fsw_u8 **)&vol->upcase, &vol->upcount))==FSW_SUCCESS) {
1278 vol->upcount /= 2;
1279 #ifndef FSW_LITTLE_ENDIAN
1280 int i;
1281 for( i=0; i<vol->upcount; i++)
1282 vol->upcase[i] = fsw_u16_le_swap(vol->upcase[i]);
1283 #endif
1284 }
1285 }
1286 free_mft(&mft);
1287 return err;
1288 }
1289
1290 static int ntfs_filename_cmp(struct fsw_ntfs_volume *vol, fsw_u8 *p1, int s1, fsw_u8 *p2, int s2)
1291 {
1292 while(s1 > 0 && s2 > 0) {
1293 fsw_u16 c1 = GETU16(p1,0);
1294 fsw_u16 c2 = GETU16(p2,0);
1295 if(c1 < 0x80 || c2 < 0x80) {
1296 if(c1 < 0x80) c1 = upcase[c1];
1297 if(c2 < 0x80) c2 = upcase[c2];
1298 } else {
1299 /*
1300 * Only load upcase table if both char is international.
1301 * We assume international char never upcased to ASCII.
1302 */
1303 if(!vol->upcase) {
1304 load_upcase(vol);
1305 if(!vol->upcase) {
1306 /* use raw value & prevent load again */
1307 vol->upcase = upcase;
1308 vol->upcount = 0;
1309 }
1310 }
1311 if(c1 < vol->upcount) c1 = vol->upcase[c1];
1312 if(c2 < vol->upcount) c2 = vol->upcase[c2];
1313 }
1314 if(c1 < c2)
1315 return -1;
1316 if(c1 > c2)
1317 return 1;
1318 p1+=2;
1319 p2+=2;
1320 s1--;
1321 s2--;
1322 }
1323 if(s1 < s2)
1324 return -1;
1325 if(s1 > s2)
1326 return 1;
1327 return 0;
1328 }
1329
1330 static fsw_status_t fsw_ntfs_create_subnode(struct fsw_ntfs_dnode *dno, fsw_u8 *buf, struct fsw_dnode **child_dno)
1331 {
1332 fsw_u64 mftno = GETU64(buf, 0) & MFTMASK;
1333 if(mftno < MFTNO_META)
1334 return FSW_NOT_FOUND;
1335
1336 int type = GETU32(buf, 0x48) & 0x10000000 ? FSW_DNODE_TYPE_DIR: FSW_DNODE_TYPE_FILE;
1337 struct fsw_string s;
1338 s.type = FSW_STRING_TYPE_UTF16_LE;
1339 s.len = GETU8(buf, 0x50);
1340 s.size = s.len * 2;
1341 s.data = buf + 0x52;
1342
1343 return fsw_dnode_create(&dno->g, mftno, type, &s, child_dno);
1344 }
1345
1346 static fsw_u8 *fsw_ntfs_read_index_block(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 block)
1347 {
1348 if(dno->cbuf==NULL) {
1349 if(fsw_alloc(dno->idxsz, &dno->cbuf) != FSW_SUCCESS)
1350 return NULL;
1351 } else if(block == dno->cvcn)
1352 return dno->cbuf;
1353
1354 dno->cvcn = BADVCN;
1355 if(fsw_ntfs_read_buffer(vol, dno, dno->cbuf, (block-1)*dno->idxsz, dno->idxsz) != dno->idxsz)
1356 return NULL;
1357 if(fixup(dno->cbuf, "INDX", 1<<vol->sctbits, dno->idxsz) != FSW_SUCCESS)
1358 return NULL;
1359
1360 dno->cvcn = block;
1361 return dno->cbuf;
1362 }
1363
1364 static fsw_status_t fsw_ntfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *lookup_name, struct fsw_dnode **child_dno)
1365 {
1366 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
1367 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1368 int depth = 0;
1369 struct fsw_string s;
1370 fsw_u8 *buf;
1371 int len;
1372 int off;
1373 fsw_status_t err;
1374 fsw_u64 block;
1375
1376 *child_dno = NULL;
1377 err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF16_LE, lookup_name);
1378 if(err)
1379 return err;
1380
1381 /* start from AT_INDEX_ROOT */
1382 buf = dno->idxroot + 16;
1383 len = dno->rootsz - 16;
1384 if(len < 0x18)
1385 goto notfound;
1386
1387 while(depth < 10) {
1388 /* real index size */
1389 if(GETU32(buf, 4) < len)
1390 len = GETU32(buf, 4);
1391
1392 /* skip index header */
1393 off = GETU32(buf, 0);
1394 if(off >= len)
1395 goto notfound;
1396
1397 block = 0;
1398 while(off + 0x18 <= len) {
1399 int flag = GETU8(buf, off+12);
1400 int next = off + GETU16(buf, off+8);
1401 int cmp;
1402
1403 if(flag & 2) {
1404 /* the end of index entry */
1405 cmp = -1;
1406 Print(L"depth %d len %x off %x flag %x next %x cmp %d\n", depth, len, off, flag, next, cmp);
1407 } else {
1408 int nlen = GETU8(buf, off+0x50);
1409 fsw_u8 *name = buf+off+0x52;
1410 cmp = ntfs_filename_cmp(vol, s.data, s.len, name, nlen);
1411 Print(L"depth %d len %x off %x flag %x next %x cmp %d name %d[%.*ls]\n", depth, len, off, flag, next, cmp, nlen, nlen, name);
1412 }
1413
1414 if(cmp == 0) {
1415 fsw_strfree(&s);
1416 return fsw_ntfs_create_subnode(dno, buf+off, child_dno);
1417 } else if(cmp < 0) {
1418 if(!(flag & 1) || !dno->has_idxtree)
1419 goto notfound;
1420 block = GETU64(buf, next-8) + 1;
1421 break;
1422 } else { /* cmp > 0 */
1423 off = next;
1424 }
1425 }
1426 if(!block)
1427 break;
1428
1429 if(!(buf = fsw_ntfs_read_index_block(vol, dno, block)))
1430 break;
1431 buf += 24;
1432 len = dno->idxsz - 24;
1433 depth++;
1434 }
1435
1436 notfound:
1437 fsw_strfree(&s);
1438 return FSW_NOT_FOUND;
1439 }
1440
1441 static inline void set_shand_pos( struct fsw_shandle *shand, int block, int off)
1442 {
1443 shand->pos = (((fsw_u64)block) << 32) + off;
1444 }
1445
1446 static inline int test_idxbmp(struct fsw_ntfs_dnode *dno, int block)
1447 {
1448 int mask;
1449 if(dno->idxbmp==NULL)
1450 return 1;
1451 block--;
1452 mask = 1 << (block & 7);
1453 block >>= 3;
1454 if(block > dno->bmpsz)
1455 return 0;
1456 return dno->idxbmp[block] & mask;
1457 }
1458
1459 #define shand_pos(x,y) (((fsw_u64)(x)<<32)|(y))
1460 static fsw_status_t fsw_ntfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_shandle *shand, struct fsw_dnode **child_dno)
1461 {
1462 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
1463 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1464 /*
1465 * high 32 bit: index block#
1466 * 0 --> index root
1467 * >0 --> vcn+1
1468 * low 32 bit: index offset
1469 */
1470 int off = shand->pos & 0xFFFFFFFF;
1471 int block = shand->pos >> 32;
1472 int mblocks;
1473
1474 mblocks = FSW_U64_DIV(dno->fsize, dno->idxsz);
1475
1476 while(block <= mblocks) {
1477 fsw_u8 *buf;
1478 int len;
1479 if(block == 0) {
1480 /* AT_INDEX_ROOT */
1481 buf = dno->idxroot + 16;
1482 len = dno->rootsz - 16;
1483 if(len < 0x18)
1484 goto miss;
1485 } else if(!test_idxbmp(dno, block) || !(buf = fsw_ntfs_read_index_block(vol, dno, block)))
1486 {
1487 /* unused or bad index block */
1488 goto miss;
1489 } else {
1490 /* AT_INDEX_ALLOCATION block */
1491 buf += 24;
1492 len = dno->idxsz - 24;
1493 }
1494 if(GETU32(buf, 4) < len)
1495 len = GETU32(buf, 4);
1496 if(off == 0)
1497 off = GETU32(buf, 0);
1498 Print(L"block %d len %x off %x\n", block, len, off);
1499 while(off + 0x18 <= len) {
1500 int flag = GETU8(buf, off+12);
1501 if(flag & 2) break;
1502 int next = off + GETU16(buf, off+8);
1503 Print(L"flag %x next %x nt %x [%.*ls]\n", flag, next, GETU8(buf, off+0x51), GETU8(buf, off+0x50), buf+off+0x52);
1504 if((GETU8(buf, off+0x51) != 2)) {
1505 /* LONG FILE NAME */
1506 fsw_status_t err = fsw_ntfs_create_subnode(dno, buf+off, child_dno);
1507 if(err != FSW_NOT_FOUND) {
1508 set_shand_pos(shand, block, next);
1509 return err;
1510 }
1511 // skip internal MFT record
1512 }
1513 off = next;
1514 }
1515 miss:
1516 if(!dno->has_idxtree)
1517 break;
1518 block++;
1519 off = 0;
1520 }
1521 set_shand_pos(shand, mblocks+1, 0);
1522 return FSW_NOT_FOUND;
1523 }
1524
1525 static fsw_status_t fsw_ntfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *link)
1526 {
1527 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1528 fsw_u8 *name;
1529 int i;
1530 int len;
1531
1532 if(!dno->islink)
1533 return FSW_UNSUPPORTED;
1534
1535 name = dno->cbuf + 0x10 + GETU16(dno->cbuf, 8);
1536 len = GETU16(dno->cbuf, 10);
1537 if(GETU32(dno->cbuf, 0) == 0xa000000c)
1538 name += 4;
1539
1540 for(i=0; i<len; i+=2)
1541 if(GETU16(name, i)=='\\')
1542 *(fsw_u16 *)(name+i) = fsw_u16_le_swap('/');
1543
1544 if(len > 6 && GETU16(name,0)=='/' && GETU16(name,2)=='?' &&
1545 GETU16(name,4)=='?' && GETU16(name,6)=='/' &&
1546 GETU16(name,10)==':' && GETU16(name,12)=='/' &&
1547 (GETU16(name,8)|0x20)>='a' && (GETU16(name,8)|0x20)<='z')
1548 {
1549 len -= 12;
1550 name += 12;
1551 }
1552 struct fsw_string s;
1553 s.type = FSW_STRING_TYPE_UTF16_LE;
1554 s.size = len;
1555 s.len = len/2;
1556 s.data = name;
1557 return fsw_strdup_coerce(link, volg->host_string_type, &s);
1558 }
1559
1560 //
1561 // Dispatch Table
1562 //
1563
1564 struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ntfs) = {
1565 { FSW_STRING_TYPE_UTF8, 4, 4, "ntfs" },
1566 sizeof(struct fsw_ntfs_volume),
1567 sizeof(struct fsw_ntfs_dnode),
1568
1569 fsw_ntfs_volume_mount,
1570 fsw_ntfs_volume_free,
1571 fsw_ntfs_volume_stat,
1572 fsw_ntfs_dnode_fill,
1573 fsw_ntfs_dnode_free,
1574 fsw_ntfs_dnode_stat,
1575 fsw_ntfs_get_extent,
1576 fsw_ntfs_dir_lookup,
1577 fsw_ntfs_dir_read,
1578 fsw_ntfs_readlink,
1579 };
1580
1581 // EOF