]> code.delx.au - refind/blob - filesystems/fsw_ntfs.c
Previous commit broke loading of EFI drivers with SB active; fix it.
[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 int olen;
375
376 if(attribute_ondisk(ptr, len) == 0) {
377 /* EMBEDED DATA */
378 attribute_get_embeded(ptr, len, &ptr, &len);
379 *olenp = len;
380 if(optrp) {
381 *optrp = AllocatePool(len);
382 fsw_memcpy(*optrp, ptr, len);
383 }
384 return FSW_SUCCESS;
385 }
386
387 olen = attribute_size(ptr, len);
388 *olenp = olen;
389 if(!optrp)
390 return FSW_SUCCESS;
391
392 fsw_u8 *buf = AllocatePool(olen);
393 fsw_memzero(buf, olen);
394 *optrp = buf;
395
396 attribute_get_rle(ptr, len, &ptr, &len);
397
398 fsw_u64 pos = 0;
399 int clustersize = 1<<vol->clbits;
400 fsw_u64 lcn, cnt;
401
402 while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
403 if(lcn) {
404 for(; cnt>0; lcn++, cnt--) {
405 fsw_u8 *block;
406 if (fsw_block_get(&vol->g, lcn, 0, (void **)&block) != FSW_SUCCESS)
407 {
408 FreePool(*optrp);
409 *optrp = NULL;
410 *olenp = 0;
411 return FSW_VOLUME_CORRUPTED;
412 }
413 fsw_memcpy(buf, block, clustersize > olen ? olen : clustersize);
414 fsw_block_release(&vol->g, lcn, block);
415
416 buf += clustersize;
417 olen -= clustersize;
418 }
419 } else {
420 buf += cnt << vol->clbits;
421 olen -= cnt << vol->clbits;
422 }
423 }
424 return FSW_SUCCESS;
425 }
426
427 static void init_mft(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, fsw_u64 mftno)
428 {
429 mft->mftno = mftno;
430 mft->buf = AllocatePool(1<<vol->mftbits);
431 mft->atlst = NULL;
432 mft->atlen = 0;
433 }
434
435 static void free_mft(struct ntfs_mft *mft)
436 {
437 if(mft->buf) FreePool(mft->buf);
438 if(mft->atlst) FreePool(mft->atlst);
439 }
440
441 static fsw_status_t load_atlist(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft)
442 {
443 fsw_u8 *ptr;
444 int len;
445 fsw_status_t err = find_attribute_direct(mft->buf, 1<<vol->mftbits, AT_ATTRIBUTE_LIST, &ptr, &len);
446 if(err != FSW_SUCCESS)
447 return err;
448 return read_attribute_direct(vol, ptr, len, &mft->atlst, &mft->atlen);
449 }
450
451 static fsw_status_t read_mft(struct fsw_ntfs_volume *vol, fsw_u8 *mft, fsw_u64 mftno)
452 {
453 int l = 0;
454 int r = vol->extmap.used - 1;
455 int m;
456 fsw_u64 vcn = (mftno << vol->mftbits) >> vol->clbits;
457 struct extent_slot *e = vol->extmap.extent;
458
459 while(l <= r) {
460 m = (l+r)/2;
461 if(vcn < e[m].vcn) {
462 r = m - 1;
463 } else if(vcn >= e[m].vcn + e[m].cnt) {
464 l = m + 1;
465 } else if(vol->mftbits <= vol->clbits) {
466 fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn);
467 int offset = (mftno << vol->mftbits) & ((1<<vol->clbits)-1);
468 fsw_u8 *buffer;
469 fsw_status_t err;
470
471 if(e[m].lcn + 1 == 0)
472 return FSW_VOLUME_CORRUPTED;
473
474 if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
475 return FSW_VOLUME_CORRUPTED;
476
477 fsw_memcpy(mft, buffer+offset, 1<<vol->mftbits);
478 fsw_block_release(&vol->g, lcn, buffer);
479 return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits);
480 } else {
481 fsw_u8 *p = mft;
482 fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn);
483 fsw_u64 ecnt = e[m].cnt - (vcn - e[m].vcn);
484 int count = 1 << (vol->mftbits - vol->clbits);
485 fsw_status_t err;
486
487 if(e[m].lcn + 1 == 0)
488 return FSW_VOLUME_CORRUPTED;
489 while(count-- > 0) {
490 fsw_u8 *buffer;
491 if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
492 return FSW_VOLUME_CORRUPTED;
493 fsw_memcpy(p, buffer, 1<<vol->clbits);
494 fsw_block_release(&vol->g, lcn, buffer);
495
496 p += 1<<vol->clbits;
497 ecnt--;
498 vcn++;
499 if(count==0) break;
500 if(ecnt > 0) {
501 lcn++;
502 } else if(++m >= vol->extmap.used || e[m].vcn != vcn) {
503 return FSW_VOLUME_CORRUPTED;
504 } else {
505 lcn = e[m].lcn;
506 ecnt = e[m].cnt;
507 }
508 }
509 return fixup(mft, "FILE", 1<<vol->sctbits, 1<<vol->mftbits);
510 }
511 }
512 return FSW_NOT_FOUND;
513 }
514
515 static void init_attr(struct fsw_ntfs_volume *vol, struct ntfs_attr *attr, int type)
516 {
517 fsw_memzero(attr, sizeof(*attr));
518 attr->type = type;
519 attr->emftno = BADMFT;
520 }
521
522 static void free_attr(struct ntfs_attr *attr)
523 {
524 if(attr->emft) FreePool(attr->emft);
525 }
526
527 static fsw_status_t find_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, struct ntfs_attr *attr, fsw_u64 vcn)
528 {
529 fsw_u8 *buf = mft->buf;
530 if(mft->atlst && mft->atlen) {
531 fsw_status_t err;
532 fsw_u64 mftno;
533 int pos = 0;
534
535 err = find_attrlist_direct(mft->atlst, mft->atlen, attr->type, vcn, &mftno, &pos);
536 if(err != FSW_SUCCESS)
537 return err;
538
539 if(mftno == mft->mftno) {
540 buf = mft->buf;
541 } else if(mftno == attr->emftno && attr->emft) {
542 buf = attr->emft;
543 } else {
544 attr->emftno = BADMFT;
545 err = read_mft(vol, attr->emft, mftno);
546 if(err != FSW_SUCCESS)
547 return err;
548 attr->emftno = mftno;
549 buf = attr->emft;
550 }
551 }
552 return find_attribute_direct(buf, 1<<vol->mftbits, attr->type, &attr->ptr, &attr->len);
553 }
554
555 static fsw_status_t read_small_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, int type, fsw_u8 **optrp, int *olenp)
556 {
557 fsw_status_t err;
558 struct ntfs_attr attr;
559
560 init_attr(vol, &attr, type);
561 err = find_attribute(vol, mft, &attr, 0);
562 if(err == FSW_SUCCESS)
563 err = read_attribute_direct(vol, attr.ptr, attr.len, optrp, olenp);
564 free_attr(&attr);
565 return err;
566 }
567
568 static void add_single_mft_map(struct fsw_ntfs_volume *vol, fsw_u8 *mft)
569 {
570 fsw_u8 *ptr;
571 int len;
572
573 if(find_attribute_direct(mft, 1<<vol->mftbits, AT_DATA, &ptr, &len)!=FSW_SUCCESS)
574 return;
575
576 if(attribute_ondisk(ptr, len) == 0)
577 return;
578
579 fsw_u64 vcn = GETU64(ptr, 0x10);
580 int off = GETU16(ptr, 0x20);
581 ptr += off;
582 len -= off;
583
584 fsw_u64 pos = 0;
585 fsw_u64 lcn, cnt;
586
587 while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
588 if(lcn) {
589 int u = vol->extmap.used;
590 if(u >= vol->extmap.total) {
591 vol->extmap.total = vol->extmap.extent ? u*2 : 16;
592 struct extent_slot *e = AllocatePool(vol->extmap.total * sizeof(struct extent_slot));
593 if(vol->extmap.extent) {
594 fsw_memcpy(e, vol->extmap.extent, u*sizeof(struct extent_slot));
595 FreePool(vol->extmap.extent);
596 }
597 vol->extmap.extent = e;
598 }
599 vol->extmap.extent[u].vcn = vcn;
600 vol->extmap.extent[u].lcn = lcn;
601 vol->extmap.extent[u].cnt = cnt;
602 vol->extmap.used++;
603 }
604 vcn += cnt;
605 }
606 }
607
608 static void add_mft_map(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft)
609 {
610 load_atlist(vol, mft);
611 add_single_mft_map(vol, mft->buf);
612 if(mft->atlst == NULL) return;
613
614 fsw_u64 mftno;
615 int pos = 0;
616
617 fsw_u8 *emft = AllocatePool(1<<vol->mftbits);
618 while(find_attrlist_direct(mft->atlst, mft->atlen, AT_DATA, 0, &mftno, &pos) == FSW_SUCCESS) {
619 if(mftno == 0) continue;
620 if(read_mft(vol, emft, mftno)==FSW_SUCCESS)
621 add_single_mft_map(vol, emft);
622 }
623 FreePool(emft);
624 }
625
626 static int tobits(fsw_u32 val)
627 {
628 return 31 - __builtin_clz(val);
629 }
630
631 static fsw_status_t fsw_ntfs_volume_mount(struct fsw_volume *volg)
632 {
633 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
634 fsw_status_t err;
635 fsw_u8 *buffer;
636 int sector_size;
637 int cluster_size;
638 signed char tmp;
639 fsw_u64 mft_start[2];
640 struct ntfs_mft mft0;
641
642 fsw_memzero((char *)vol+sizeof(*volg), sizeof(*vol)-sizeof(*volg));
643 fsw_set_blocksize(volg, 512, 512);
644 if ((err = fsw_block_get(volg, 0, 0, (void **)&buffer)) != FSW_SUCCESS)
645 return FSW_UNSUPPORTED;
646
647 if (!fsw_memeq(buffer+3, "NTFS ", 8))
648 return FSW_UNSUPPORTED;
649
650 sector_size = GETU16(buffer, 0xB);
651 if(sector_size==0 || (sector_size & (sector_size-1)) || sector_size < 0x100 || sector_size > 0x1000)
652 return FSW_UNSUPPORTED;
653
654 vol->sctbits = tobits(sector_size);
655 vol->totalbytes = GETU64(buffer, 0x28) << vol->sctbits;
656 Print(L"NTFS size=%ld M\n", vol->totalbytes>>20);
657
658 cluster_size = GETU8(buffer, 0xD) * sector_size;
659 if(cluster_size==0 || (cluster_size & (cluster_size-1)) || cluster_size > 0x10000)
660 return FSW_UNSUPPORTED;
661
662 vol->clbits = tobits(cluster_size);
663
664 tmp = GETU8(buffer, 0x40);
665 if(tmp > 0)
666 vol->mftbits = vol->clbits + tobits(tmp);
667 else
668 vol->mftbits = -tmp;
669
670 if(vol->mftbits < vol->sctbits || vol->mftbits > 16)
671 return FSW_UNSUPPORTED;
672
673 tmp = GETU8(buffer, 0x44);
674 if(tmp > 0)
675 vol->idxbits = vol->clbits + tobits(tmp);
676 else
677 vol->idxbits = -tmp;
678
679 if(vol->idxbits < vol->sctbits || vol->idxbits > 16)
680 return FSW_UNSUPPORTED;
681
682 mft_start[0] = GETU64(buffer, 0x30);
683 mft_start[1] = GETU64(buffer, 0x38);
684
685 fsw_block_release(volg, 0, (void *)buffer);
686 fsw_set_blocksize(volg, cluster_size, cluster_size);
687
688 init_mft(vol, &mft0, MFTNO_MFT);
689 for(tmp=0; tmp<2; tmp++) {
690 fsw_u8 *ptr = mft0.buf;
691 int len = 1 << vol->mftbits;
692 fsw_u64 lcn = mft_start[tmp];
693 while(len > 0) {
694 if ((err = fsw_block_get(volg, lcn, 0, (void **)&buffer)) != FSW_SUCCESS)
695 {
696 free_mft(&mft0);
697 return FSW_UNSUPPORTED;
698 }
699 int n = vol->mftbits < vol->clbits ? (1<<vol->mftbits) : cluster_size;
700 fsw_memcpy(ptr, buffer, n);
701 fsw_block_release(volg, lcn, (void *)buffer);
702 ptr += n;
703 len -= n;
704 lcn++;
705 }
706 err = fixup(mft0.buf, "FILE", sector_size, 1<<vol->mftbits);
707 if(err != FSW_SUCCESS)
708 return err;
709 }
710
711 add_mft_map(vol, &mft0);
712
713 {
714 int i;
715 for(i=0; i<vol->extmap.used; i++)
716 Print(L"extent %d: vcn=%lx lcn=%lx len=%lx\n",
717 i,
718 vol->extmap.extent[i].vcn,
719 vol->extmap.extent[i].lcn,
720 vol->extmap.extent[i].cnt);
721 }
722
723 free_mft(&mft0);
724
725 /* load $Volume name */
726 init_mft(vol, &mft0, MFTNO_VOLUME);
727 fsw_u8 *ptr;
728 int len;
729 if(read_mft(vol, mft0.buf, MFTNO_VOLUME)==FSW_SUCCESS &&
730 find_attribute_direct(mft0.buf, 1<<vol->mftbits, AT_VOLUME_NAME, &ptr, &len)==FSW_SUCCESS &&
731 GETU8(ptr, 8)==0)
732 {
733 struct fsw_string s;
734 s.type = FSW_STRING_TYPE_UTF16_LE;
735 s.size = GETU16(ptr, 0x10);
736 s.len = s.size / 2;
737 s.data = ptr + GETU16(ptr, 0x14);
738 Print(L"Volume name [%.*ls]\n", s.len, s.data);
739 err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s);
740 }
741 free_mft(&mft0);
742
743 err = fsw_dnode_create_root(volg, MFTNO_ROOT, &volg->root);
744 if (err)
745 return err;
746
747 return FSW_SUCCESS;
748 }
749
750 static void fsw_ntfs_volume_free(struct fsw_volume *volg)
751 {
752 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
753 if(vol->extmap.extent)
754 FreePool(vol->extmap.extent);
755 if(vol->upcase && vol->upcase != upcase)
756 FreePool((void *)vol->upcase);
757 }
758
759 static fsw_status_t fsw_ntfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb)
760 {
761 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
762 sb->total_bytes = vol->totalbytes;
763 /* reading through cluster bitmap is too costly */
764 sb->free_bytes = 0;
765 return FSW_SUCCESS;
766 }
767
768 static fsw_status_t fsw_ntfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog)
769 {
770 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
771 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
772 fsw_status_t err;
773 int len;
774
775 fsw_memzero((char *)dno+sizeof(*dnog), sizeof(*dno)-sizeof(*dnog));
776 init_mft(vol, &dno->mft, dno->g.dnode_id);
777 err = read_mft(vol, dno->mft.buf, dno->g.dnode_id);
778 if(err != FSW_SUCCESS)
779 return err;
780
781 len = GETU8(dno->mft.buf, 22);
782 if( (len & 1) == 0 )
783 return FSW_NOT_FOUND;
784
785 load_atlist(vol, &dno->mft);
786
787 if(read_small_attribute(vol, &dno->mft, AT_REPARSE_POINT, &dno->cbuf, &len)==FSW_SUCCESS) {
788 switch(GETU32(dno->cbuf, 0)) {
789 case 0xa0000003:
790 case 0xa000000c:
791 dno->g.size = len;
792 dno->g.type = FSW_DNODE_TYPE_SYMLINK;
793 dno->islink = 1;
794 dno->fsize = len;
795 return FSW_SUCCESS;
796 default:
797 FreePool(dno->cbuf);
798 dno->cbuf = NULL;
799 };
800 }
801
802 if( (len & 2) ) {
803 dno->g.type = FSW_DNODE_TYPE_DIR;
804 /* $INDEX_ROOT:$I30 must present */
805 err = read_small_attribute(vol, &dno->mft, AT_INDEX_ROOT|AT_I30, &dno->idxroot, &dno->rootsz);
806 if(err != FSW_SUCCESS)
807 {
808 Print(L"dno_fill INDEX_ROOT:$I30 error %d\n", err);
809 return err;
810 }
811
812 dno->idxsz = GETU32(dno->idxroot, 8);
813 if(dno->idxsz == 0)
814 dno->idxsz = 1<<vol->idxbits;
815
816 /* $Bitmap:$I30 is optional */
817 err = read_small_attribute(vol, &dno->mft, AT_BITMAP|AT_I30, &dno->idxbmp, &dno->bmpsz);
818 if(err != FSW_SUCCESS && err != FSW_NOT_FOUND)
819 {
820 Print(L"dno_fill $Bitmap:$I30 error %d\n", err);
821 return err;
822 }
823
824 /* $INDEX_ALLOCATION:$I30 is optional */
825 init_attr(vol, &dno->attr, AT_INDEX_ALLOCATION|AT_I30);
826 err = find_attribute(vol, &dno->mft, &dno->attr, 0);
827 if(err == FSW_SUCCESS) {
828 dno->has_idxtree = 1;
829 dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len);
830 dno->finited = dno->fsize;
831 } else if(err != FSW_NOT_FOUND) {
832 Print(L"dno_fill $INDEX_ALLOCATION:$I30 error %d\n", err);
833 return err;
834 }
835
836 } else {
837 dno->g.type = FSW_DNODE_TYPE_FILE;
838 init_attr(vol, &dno->attr, AT_DATA);
839 err = find_attribute(vol, &dno->mft, &dno->attr, 0);
840 if(err != FSW_SUCCESS)
841 {
842 Print(L"dno_fill AT_DATA error %d\n", err);
843 return err;
844 }
845 dno->embeded = !attribute_ondisk(dno->attr.ptr, dno->attr.len);
846 dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len);
847 dno->finited = attribute_inited_size(dno->attr.ptr, dno->attr.len);
848 if(attribute_encrypted(dno->attr.ptr, dno->attr.len))
849 dno->unreadable = 1;
850 else if(attribute_compressed_future(dno->attr.ptr, dno->attr.len))
851 dno->unreadable = 1;
852 else if(attribute_compressed(dno->attr.ptr, dno->attr.len))
853 dno->compressed = 1;
854 dno->cvcn = BADVCN;
855 dno->g.size = dno->fsize;
856 }
857 return FSW_SUCCESS;
858 }
859
860 static void fsw_ntfs_dnode_free(struct fsw_volume *vol, struct fsw_dnode *dnog)
861 {
862 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
863 free_mft(&dno->mft);
864 free_attr(&dno->attr);
865 if(dno->idxroot)
866 FreePool(dno->idxroot);
867 if(dno->idxbmp)
868 FreePool(dno->idxbmp);
869 if(dno->cbuf)
870 FreePool(dno->cbuf);
871 }
872
873 static fsw_u32 get_ntfs_time(fsw_u8 *buf, int pos)
874 {
875 fsw_u64 t = GETU64(buf, pos);
876 t = FSW_U64_DIV(t, 10000000);
877 t -= 134774ULL * 86400;
878 return t;
879 }
880
881 static fsw_status_t fsw_ntfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb)
882 {
883 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
884 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
885 fsw_status_t err;
886 fsw_u16 attr;
887 fsw_u8 *ptr;
888 int len;
889
890 err = find_attribute_direct(dno->mft.buf, 1<<vol->mftbits, AT_STANDARD_INFORMATION, &ptr, &len);
891
892 if(err != FSW_SUCCESS || GETU8(ptr, 8))
893 return err;
894
895 ptr += GETU16(ptr, 0x14);
896 attr = GETU8(ptr, 0x20); /* only lower 8 of 32 bit is used */
897 attr &= EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE;
898 /* add DIR again if symlink */
899 if(GETU8(dno->mft.buf, 22) & 2)
900 attr |= EFI_FILE_DIRECTORY;
901
902 fsw_store_attr_efi(sb, attr);
903 sb->used_bytes = dno->fsize;
904 fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, get_ntfs_time(ptr, 24));
905 fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, get_ntfs_time(ptr, 8));
906 fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, get_ntfs_time(ptr, 16));
907
908 return FSW_SUCCESS;
909 }
910
911 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)
912 {
913 fsw_status_t err;
914 if(vcn >= dno->cext.vcn && vcn < dno->cext.vcn+dno->cext.cnt) {
915 *lcnp = dno->cext.lcn + vcn - dno->cext.vcn;
916 return FSW_SUCCESS;
917 }
918 if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) {
919 err = find_attribute(vol, &dno->mft, &dno->attr, vcn);
920 if( err != FSW_SUCCESS )
921 return err;
922 if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn))
923 return FSW_VOLUME_CORRUPTED;
924 }
925 fsw_u8 *ptr = dno->attr.ptr;
926 int len = dno->attr.len;
927 fsw_u64 pos = 0;
928 fsw_u64 lcn, cnt;
929 fsw_u64 svcn = attribute_first_vcn(ptr, len);
930 fsw_u64 evcn = attribute_last_vcn(ptr, len) + 1;
931 int off = GETU16(ptr, 0x20);
932 ptr += off;
933 len -= off;
934 while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) {
935 if(vcn >= svcn && vcn < svcn+cnt) {
936 dno->cext.vcn = svcn;
937 dno->cext.lcn = lcn;
938 dno->cext.cnt = cnt;
939 if(lcn == 0)
940 return FSW_NOT_FOUND;
941 *lcnp = lcn + vcn - svcn;
942 return FSW_SUCCESS;
943 }
944 svcn += cnt;
945 if(svcn >= evcn)
946 break;
947 }
948 return FSW_NOT_FOUND;
949 }
950
951 static int fsw_ntfs_read_buffer(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u8 *buf, fsw_u64 offset, int size)
952 {
953 if(dno->embeded) {
954 fsw_u8 *ptr;
955 int len;
956 attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len);
957 if(size > len)
958 size = len;
959 fsw_memcpy(buf, ptr, size);
960 return size;
961 }
962
963 if(!dno->attr.ptr || !dno->attr.len) {
964 Print(L"BAD--------: attr.ptr %p attr.len %x cleared\n", dno->attr.ptr, dno->attr.len);
965 if(find_attribute(vol, &dno->mft, &dno->attr, 0) != FSW_SUCCESS)
966 return 0;
967 }
968
969 if(offset >= dno->fsize)
970 return 0;
971 if(offset + size >= dno->fsize)
972 size = dno->fsize - offset;
973
974 if(offset >= dno->finited) {
975 fsw_memzero(buf, size);
976 return size;
977 }
978
979 int ret = 0;
980 int zsize = 0;
981 if(offset + size >= dno->finited) {
982 zsize = offset + size - dno->finited;
983 size = dno->finited - offset;
984 }
985
986 fsw_u64 vcn = offset >> vol->clbits;
987 int boff = offset & ((1<<vol->clbits)-1);
988 fsw_u64 lcn = 0;
989
990 while(size > 0) {
991 fsw_u8 *block;
992 fsw_status_t err;
993 int bsz;
994
995 err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn, &lcn);
996 if (err != FSW_SUCCESS) break;
997
998 err = fsw_block_get(&vol->g, lcn, 0, (void **)&block);
999 if (err != FSW_SUCCESS) break;
1000
1001 bsz = (1<<vol->clbits) - boff;
1002 if(bsz > size)
1003 bsz = size;
1004
1005 fsw_memcpy(buf, block+boff, bsz);
1006 fsw_block_release(&vol->g, lcn, block);
1007
1008 ret += bsz;
1009 buf += bsz;
1010 size -= bsz;
1011 boff = 0;
1012 }
1013 if(size==0 && zsize > 0) {
1014 fsw_memzero(buf, zsize);
1015 ret += zsize;
1016 }
1017 return ret;
1018 }
1019
1020 static fsw_status_t fsw_ntfs_get_extent_embeded(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
1021 {
1022 if(extent->log_start > 0)
1023 return FSW_NOT_FOUND;
1024 extent->log_count = 1;
1025 extent->buffer = AllocatePool(1<<vol->clbits);
1026 fsw_u8 *ptr;
1027 int len;
1028 attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len);
1029 if(len > (1<<vol->clbits))
1030 len = 1<<vol->clbits;
1031 fsw_memcpy(extent->buffer, ptr, len);
1032 extent->type = FSW_EXTENT_TYPE_BUFFER;
1033 return FSW_SUCCESS;
1034 }
1035
1036 static int ntfs_decomp_1page(fsw_u8 *src, int slen, fsw_u8 *dst) {
1037 int soff = 0;
1038 int doff = 0;
1039 while(soff < slen) {
1040 int j;
1041 int tag = src[soff++];
1042 for(j = 0; j < 8 && soff < slen; j++) {
1043 if(tag & (1<<j)){
1044 int len;
1045 int back;
1046 int bits;
1047
1048 if(!doff || soff + 2 > slen)
1049 return -1;
1050 len = GETU16(src, soff); soff += 2;
1051 bits = __builtin_clz((doff-1)>>3)-19;
1052 back = (len >> bits) + 1;
1053 len = (len & ((1<<bits)-1)) + 3;
1054 if(doff < back || doff + len > 0x1000)
1055 return -1;
1056 while(len-- > 0) {
1057 dst[doff] = dst[doff-back];
1058 doff++;
1059 }
1060 } else {
1061 if(doff >= 0x1000)
1062 return -1;
1063 dst[doff++] = src[soff++];
1064 }
1065 }
1066 }
1067 return doff;
1068 }
1069
1070 static int ntfs_decomp(fsw_u8 *src, int slen, fsw_u8 *dst, int npage) {
1071 fsw_u8 *se = src + slen;
1072 fsw_u8 *de = dst + (npage<<12);
1073 int i;
1074 for(i=0; i<npage; i++) {
1075 fsw_u16 slen = GETU16(src, 0);
1076 int comp = slen & 0x8000;
1077 slen = (slen&0xfff)+1;
1078 src += 2;
1079
1080 if(src + slen > se || dst + 0x1000 > de)
1081 return -1;
1082
1083 if(!comp) {
1084 fsw_memcpy(dst, src, slen);
1085 if(slen < 0x1000)
1086 fsw_memzero(dst+slen, 0x1000-slen);
1087 } else if(slen == 1) {
1088 fsw_memzero(dst, 0x1000);
1089 } else {
1090 int dlen = ntfs_decomp_1page(src, slen, dst);
1091 if(dlen < 0)
1092 return -1;
1093 if(dlen < 0x1000)
1094 fsw_memzero(dst+dlen, 0x1000-dlen);
1095 }
1096 src += slen;
1097 dst += 0x1000;
1098 }
1099 return 0;
1100 }
1101
1102 static fsw_status_t fsw_ntfs_get_extent_compressed(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
1103 {
1104 if(vol->clbits > 16)
1105 return FSW_VOLUME_CORRUPTED;
1106
1107 if((extent->log_start << vol->clbits) > dno->fsize)
1108 return FSW_NOT_FOUND;
1109
1110 int i;
1111 fsw_u64 vcn = extent->log_start & ~15;
1112
1113 if(vcn == dno->cvcn)
1114 goto hit;
1115 dno->cvcn = vcn;
1116 dno->cperror = 0;
1117 dno->cpfull = 0;
1118 dno->cpzero = 0;
1119
1120 for(i=0; i<16; i++) {
1121 fsw_status_t err;
1122 err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn+i, &dno->clcn[i]);
1123 if(err == FSW_NOT_FOUND) {
1124 break;
1125 } else if(err != FSW_SUCCESS) {
1126 Print(L"BAD LCN\n");
1127 dno->cperror = 1;
1128 return FSW_VOLUME_CORRUPTED;
1129 }
1130 }
1131 if(i == 0)
1132 dno->cpzero = 1;
1133 else if(i==16)
1134 dno->cpfull = 1;
1135 else {
1136 if(dno->cbuf == NULL)
1137 dno->cbuf = AllocatePool(16<<vol->clbits);
1138 fsw_u8 *src = AllocatePool(i << vol->clbits);
1139 int b;
1140 for(b=0; b<i; b++) {
1141 char *block;
1142 if (fsw_block_get(&vol->g, dno->clcn[b], 0, (void **)&block) != FSW_SUCCESS) {
1143 dno->cperror = 1;
1144 Print(L"Read ERROR at block %d\n", i);
1145 break;
1146 }
1147 fsw_memcpy(src+(b<<vol->clbits), block, 1<<vol->clbits);
1148 fsw_block_release(&vol->g, dno->clcn[b], block);
1149 }
1150
1151 if(dno->fsize >= ((vcn+16)<<vol->clbits))
1152 b = 16<<vol->clbits>>12;
1153 else
1154 b = (dno->fsize - (vcn << vol->clbits) + 0xfff)>>12;
1155 if(!dno->cperror && ntfs_decomp(src, i<<vol->clbits, dno->cbuf, b) < 0)
1156 dno->cperror = 1;
1157 FreePool(src);
1158 }
1159 hit:
1160 if(dno->cperror)
1161 return FSW_VOLUME_CORRUPTED;
1162 i = extent->log_start - vcn;
1163 if(dno->cpfull) {
1164 fsw_u64 lcn = dno->clcn[i];
1165 extent->phys_start = lcn;
1166 extent->log_count = 1;
1167 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
1168 for(i++, lcn++; i<16 && lcn==dno->clcn[i]; i++, lcn++)
1169 extent->log_count++;
1170 } else if(dno->cpzero) {
1171 extent->log_count = 16 - i;
1172 extent->buffer = NULL;
1173 extent->type = FSW_EXTENT_TYPE_SPARSE;
1174 } else {
1175 extent->log_count = 1;
1176 extent->buffer = AllocatePool(1<<vol->clbits);
1177 fsw_memcpy(extent->buffer, dno->cbuf + (i<<vol->clbits), 1<<vol->clbits);
1178 extent->type = FSW_EXTENT_TYPE_BUFFER;
1179 }
1180 return FSW_SUCCESS;
1181 }
1182
1183 static fsw_status_t fsw_ntfs_get_extent_sparse(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent)
1184 {
1185 fsw_status_t err;
1186
1187 if((extent->log_start << vol->clbits) > dno->fsize)
1188 return FSW_NOT_FOUND;
1189 if((extent->log_start << vol->clbits) > dno->finited)
1190 {
1191 extent->log_count = 1;
1192 extent->buffer = NULL;
1193 extent->type = FSW_EXTENT_TYPE_SPARSE;
1194 return FSW_SUCCESS;
1195 }
1196 fsw_u64 lcn;
1197 err = fsw_ntfs_dnode_get_lcn(vol, dno, extent->log_start, &lcn);
1198 if(err == FSW_NOT_FOUND) {
1199 extent->log_count = 1;
1200 extent->buffer = NULL;
1201 extent->type = FSW_EXTENT_TYPE_SPARSE;
1202 return FSW_SUCCESS;
1203 }
1204 if(err != FSW_SUCCESS)
1205 return err;
1206 extent->phys_start = lcn;
1207 extent->log_count = 1;
1208 if(extent->log_start >= dno->cext.vcn && extent->log_start < dno->cext.vcn+dno->cext.cnt)
1209 extent->log_count = dno->cext.cnt + extent->log_start - dno->cext.vcn;
1210 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
1211 return FSW_SUCCESS;
1212 }
1213
1214 static fsw_status_t fsw_ntfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_extent *extent)
1215 {
1216 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
1217 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1218
1219 if(dno->unreadable)
1220 return FSW_UNSUPPORTED;
1221 if(dno->embeded)
1222 return fsw_ntfs_get_extent_embeded(vol, dno, extent);
1223 if(dno->compressed)
1224 return fsw_ntfs_get_extent_compressed(vol, dno, extent);
1225 return fsw_ntfs_get_extent_sparse(vol, dno, extent);
1226 }
1227
1228 static fsw_status_t load_upcase(struct fsw_ntfs_volume *vol)
1229 {
1230 fsw_status_t err;
1231 struct ntfs_mft mft;
1232 init_mft(vol, &mft, MFTNO_UPCASE);
1233 err = read_mft(vol, mft.buf, MFTNO_UPCASE);
1234 if(err == FSW_SUCCESS) {
1235 if((err = read_small_attribute(vol, &mft, AT_DATA, (fsw_u8 **)&vol->upcase, &vol->upcount))==FSW_SUCCESS) {
1236 vol->upcount /= 2;
1237 #ifndef FSW_LITTLE_ENDIAN
1238 int i;
1239 for( i=0; i<vol->upcount; i++)
1240 vol->upcase[i] = fsw_u16_le_swap(vol->upcase[i]);
1241 #endif
1242 }
1243 }
1244 free_mft(&mft);
1245 return err;
1246 }
1247
1248 static int ntfs_filename_cmp(struct fsw_ntfs_volume *vol, fsw_u8 *p1, int s1, fsw_u8 *p2, int s2)
1249 {
1250 while(s1 > 0 && s2 > 0) {
1251 fsw_u16 c1 = GETU16(p1,0);
1252 fsw_u16 c2 = GETU16(p2,0);
1253 if(c1 < 0x80 || c2 < 0x80) {
1254 if(c1 < 0x80) c1 = upcase[c1];
1255 if(c2 < 0x80) c2 = upcase[c2];
1256 } else {
1257 /*
1258 * Only load upcase table if both char is international.
1259 * We assume international char never upcased to ASCII.
1260 */
1261 if(!vol->upcase) {
1262 load_upcase(vol);
1263 if(!vol->upcase) {
1264 /* use raw value & prevent load again */
1265 vol->upcase = upcase;
1266 vol->upcount = 0;
1267 }
1268 }
1269 if(c1 < vol->upcount) c1 = vol->upcase[c1];
1270 if(c2 < vol->upcount) c2 = vol->upcase[c2];
1271 }
1272 if(c1 < c2)
1273 return -1;
1274 if(c1 > c2)
1275 return 1;
1276 p1+=2;
1277 p2+=2;
1278 s1--;
1279 s2--;
1280 }
1281 if(s1 < s2)
1282 return -1;
1283 if(s1 > s2)
1284 return 1;
1285 return 0;
1286 }
1287
1288 static fsw_status_t fsw_ntfs_create_subnode(struct fsw_ntfs_dnode *dno, fsw_u8 *buf, struct fsw_dnode **child_dno)
1289 {
1290 fsw_u64 mftno = GETU64(buf, 0) & MFTMASK;
1291 if(mftno < MFTNO_META)
1292 return FSW_NOT_FOUND;
1293
1294 int type = GETU32(buf, 0x48) & 0x10000000 ? FSW_DNODE_TYPE_DIR: FSW_DNODE_TYPE_FILE;
1295 struct fsw_string s;
1296 s.type = FSW_STRING_TYPE_UTF16_LE;
1297 s.len = GETU8(buf, 0x50);
1298 s.size = s.len * 2;
1299 s.data = buf + 0x52;
1300
1301 return fsw_dnode_create(&dno->g, mftno, type, &s, child_dno);
1302 }
1303
1304 static fsw_u8 *fsw_ntfs_read_index_block(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 block)
1305 {
1306 if(dno->cbuf==NULL)
1307 dno->cbuf = AllocatePool(dno->idxsz);
1308 else if(block == dno->cvcn)
1309 return dno->cbuf;
1310
1311 dno->cvcn = 0;
1312 if(fsw_ntfs_read_buffer(vol, dno, dno->cbuf, (block-1)*dno->idxsz, dno->idxsz) != dno->idxsz)
1313 return NULL;
1314 if(fixup(dno->cbuf, "INDX", 1<<vol->sctbits, dno->idxsz) != FSW_SUCCESS)
1315 return NULL;
1316
1317 dno->cvcn = block;
1318 return dno->cbuf;
1319 }
1320
1321 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)
1322 {
1323 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
1324 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1325 int depth = 0;
1326 struct fsw_string s;
1327 fsw_u8 *buf;
1328 int len;
1329 int off;
1330 fsw_status_t err;
1331 fsw_u64 block;
1332
1333 *child_dno = NULL;
1334 err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF16_LE, lookup_name);
1335 if(err)
1336 return err;
1337
1338 /* start from AT_INDEX_ROOT */
1339 buf = dno->idxroot + 16;
1340 len = dno->rootsz - 16;
1341 if(len < 0x18)
1342 goto notfound;
1343
1344 while(depth < 10) {
1345 /* real index size */
1346 if(GETU32(buf, 4) < len)
1347 len = GETU32(buf, 4);
1348
1349 /* skip index header */
1350 off = GETU32(buf, 0);
1351 if(off >= len)
1352 goto notfound;
1353
1354 block = 0;
1355 while(off + 0x18 <= len) {
1356 int flag = GETU8(buf, off+12);
1357 int next = off + GETU16(buf, off+8);
1358 int cmp;
1359
1360 if(flag & 2) {
1361 /* the end of index entry */
1362 cmp = -1;
1363 Print(L"depth %d len %x off %x flag %x next %x cmp %d\n", depth, len, off, flag, next, cmp);
1364 } else {
1365 int nlen = GETU8(buf, off+0x50);
1366 fsw_u8 *name = buf+off+0x52;
1367 cmp = ntfs_filename_cmp(vol, s.data, s.len, name, nlen);
1368 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);
1369 }
1370
1371 if(cmp == 0) {
1372 fsw_strfree(&s);
1373 return fsw_ntfs_create_subnode(dno, buf+off, child_dno);
1374 } else if(cmp < 0) {
1375 if(!(flag & 1) || !dno->has_idxtree)
1376 goto notfound;
1377 block = GETU64(buf, next-8) + 1;
1378 break;
1379 } else { /* cmp > 0 */
1380 off = next;
1381 }
1382 }
1383 if(!block)
1384 break;
1385
1386 if(!(buf = fsw_ntfs_read_index_block(vol, dno, block)))
1387 break;
1388 buf += 24;
1389 len = dno->idxsz - 24;
1390 depth++;
1391 }
1392
1393 notfound:
1394 fsw_strfree(&s);
1395 return FSW_NOT_FOUND;
1396 }
1397
1398 static inline void set_shand_pos( struct fsw_shandle *shand, int block, int off)
1399 {
1400 shand->pos = (((fsw_u64)block) << 32) + off;
1401 }
1402
1403 static inline int test_idxbmp(struct fsw_ntfs_dnode *dno, int block)
1404 {
1405 int mask;
1406 if(dno->idxbmp==NULL)
1407 return 1;
1408 block--;
1409 mask = 1 << (block & 7);
1410 block >>= 3;
1411 if(block > dno->bmpsz)
1412 return 0;
1413 return dno->idxbmp[block] & mask;
1414 }
1415
1416 #define shand_pos(x,y) (((fsw_u64)(x)<<32)|(y))
1417 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)
1418 {
1419 struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg;
1420 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1421 /*
1422 * high 32 bit: index block#
1423 * 0 --> index root
1424 * >0 --> vcn+1
1425 * low 32 bit: index offset
1426 */
1427 int off = shand->pos & 0xFFFFFFFF;
1428 int block = shand->pos >> 32;
1429 int mblocks;
1430
1431 mblocks = FSW_U64_DIV(dno->fsize, dno->idxsz);
1432
1433 while(block <= mblocks) {
1434 fsw_u8 *buf;
1435 int len;
1436 if(block == 0) {
1437 /* AT_INDEX_ROOT */
1438 buf = dno->idxroot + 16;
1439 len = dno->rootsz - 16;
1440 if(len < 0x18)
1441 goto miss;
1442 } else if(!test_idxbmp(dno, block) || !(buf = fsw_ntfs_read_index_block(vol, dno, block)))
1443 {
1444 /* unused or bad index block */
1445 goto miss;
1446 } else {
1447 /* AT_INDEX_ALLOCATION block */
1448 buf += 24;
1449 len = dno->idxsz - 24;
1450 }
1451 if(GETU32(buf, 4) < len)
1452 len = GETU32(buf, 4);
1453 if(off == 0)
1454 off = GETU32(buf, 0);
1455 Print(L"block %d len %x off %x\n", block, len, off);
1456 while(off + 0x18 <= len) {
1457 int flag = GETU8(buf, off+12);
1458 if(flag & 2) break;
1459 int next = off + GETU16(buf, off+8);
1460 Print(L"flag %x next %x nt %x [%.*ls]\n", flag, next, GETU8(buf, off+0x51), GETU8(buf, off+0x50), buf+off+0x52);
1461 if((GETU8(buf, off+0x51) != 2)) {
1462 /* LONG FILE NAME */
1463 fsw_status_t err = fsw_ntfs_create_subnode(dno, buf+off, child_dno);
1464 if(err != FSW_NOT_FOUND) {
1465 set_shand_pos(shand, block, next);
1466 return err;
1467 }
1468 // skip internal MFT record
1469 }
1470 off = next;
1471 }
1472 miss:
1473 if(!dno->has_idxtree)
1474 break;
1475 block++;
1476 off = 0;
1477 }
1478 set_shand_pos(shand, mblocks+1, 0);
1479 return FSW_NOT_FOUND;
1480 }
1481
1482 static fsw_status_t fsw_ntfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *link)
1483 {
1484 struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog;
1485 fsw_u8 *name;
1486 int i;
1487 int len;
1488
1489 if(!dno->islink)
1490 return FSW_UNSUPPORTED;
1491
1492 name = dno->cbuf + 0x10 + GETU16(dno->cbuf, 8);
1493 len = GETU16(dno->cbuf, 10);
1494 if(GETU32(dno->cbuf, 0) == 0xa000000c)
1495 name += 4;
1496
1497 for(i=0; i<len; i+=2)
1498 if(GETU16(name, i)=='\\')
1499 *(fsw_u16 *)(name+i) = fsw_u16_le_swap('/');
1500
1501 if(len > 6 && GETU16(name,0)=='/' && GETU16(name,2)=='?' &&
1502 GETU16(name,4)=='?' && GETU16(name,6)=='/' &&
1503 GETU16(name,10)==':' && GETU16(name,12)=='/' &&
1504 (GETU16(name,8)|0x20)>='a' && (GETU16(name,8)|0x20)<='z')
1505 {
1506 len -= 12;
1507 name += 12;
1508 }
1509 struct fsw_string s;
1510 s.type = FSW_STRING_TYPE_UTF16_LE;
1511 s.size = len;
1512 s.len = len/2;
1513 s.data = name;
1514 return fsw_strdup_coerce(link, volg->host_string_type, &s);
1515 }
1516
1517 //
1518 // Dispatch Table
1519 //
1520
1521 struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ntfs) = {
1522 { FSW_STRING_TYPE_UTF8, 4, 4, "ntfs" },
1523 sizeof(struct fsw_ntfs_volume),
1524 sizeof(struct fsw_ntfs_dnode),
1525
1526 fsw_ntfs_volume_mount,
1527 fsw_ntfs_volume_free,
1528 fsw_ntfs_volume_stat,
1529 fsw_ntfs_dnode_fill,
1530 fsw_ntfs_dnode_free,
1531 fsw_ntfs_dnode_stat,
1532 fsw_ntfs_get_extent,
1533 fsw_ntfs_dir_lookup,
1534 fsw_ntfs_dir_read,
1535 fsw_ntfs_readlink,
1536 };
1537
1538 // EOF