|
|
1.1 root 1: /* vim: set sw=4 :*/
2: /*
3: * GRUB -- GRand Unified Bootloader
4: * Copyright (C) 1999 Free Software Foundation, Inc.
5: *
6: * This program is free software; you can redistribute it and/or modify
7: * it under the terms of the GNU General Public License as published by
8: * the Free Software Foundation; either version 2 of the License, or
9: * (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with this program; if not, write to the Free Software
18: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19: * MA 02110-1301, USA.
20: */
21:
22: /*
23: * Samuel Leo <samuel@_.remove.me._szonline.net>
24: * Limitations:
25: * 1. Only 32 bit size support
26: * 2. don't support >1k MFT record size, >16k INDEX record size
27: * 3. don't support recursive at_attribute_list
28: * 4. don't support compressed attribute other than Datastream
29: * 5. all MFT's at_attribute_list must resident at first run list
30: * 6. don't support journaling
31: * 7. don't support EFS encryption
32: * 8. don't support mount point and junction
33: */
34: #ifdef FSYS_NTFS
35:
36: //#define DEBUG_NTFS 1
37:
38: /*
39: #define NO_ATTRIBUTE_LIST 1
40: totally disable at_attribute_list support,
41: if no compressed/fragment file and MFT,
42: not recommended
43: #define NO_NON_RESIDENT_ATTRIBUTE_LIST 1
44: disable non-resident at_attribute_list support,
45: if no huge compressed/fragment file and MFT
46: #define NO_NTFS_DECOMPRESSION 1
47: disable ntfs compressed file support
48: #define NO_ALTERNATE_DATASTREAM 1
49: disable ntfs alternate datastream support
50: */
51:
52: #include "shared.h"
53: #include "filesys.h"
54:
55: #ifdef STAGE1_5
56: /* safe turn off non-resident attribute list if MFT fragments < 4000 */
57: //#define NO_NON_RESIDENT_ATTRIBUTE_LIST 1
58: #define NO_NTFS_DECOMPRESSION 1
59: #endif
60:
61: #define MAX_MFT_RECORD_SIZE 1024
62: #define MAX_INDEX_RECORD_SIZE 16384
63: #define MAX_INDEX_BITMAP_SIZE 4096
64: #define DECOMP_DEST_BUFFER_SIZE 16384
65: #define DECOMP_SOURCE_BUFFER_SIZE (8192+2)
66: #define MAX_DIR_DEPTH 64
67:
68: /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
69: #define DEV_BSIZE 512
70:
71: /* include/linux/fs.h */
72: #define BLOCK_SIZE 512
73:
74: #define WHICH_SUPER 1
75: #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
76:
77: /* include/asm-i386/type.h */
78: typedef __signed__ char __s8;
79: typedef unsigned char __u8;
80: typedef __signed__ short __s16;
81: typedef unsigned short __u16;
82: typedef __signed__ int __s32;
83: typedef unsigned int __u32;
84: typedef __signed__ long long __s64;
85: typedef unsigned long long __u64;
86:
87: #define FILE_MFT 0
88: #define FILE_MFTMIRR 1
89: #define FILE_LOGFILE 2
90: #define FILE_VOLUME 3
91: #define FILE_ATTRDEF 4
92: #define FILE_ROOT 5
93: #define FILE_BITMAP 6
94: #define FILE_BOOT 7
95: #define FILE_BADCLUS 8
96: #define FILE_QUOTA 9
97: #define FILE_UPCASE 10
98:
99: #define at_standard_information 0x10
100: #define at_attribute_list 0x20
101: #define at_filename 0x30
102: #define at_security_descriptor 0x50
103: #define at_data 0x80
104: #define at_index_root 0x90
105: #define at_index_allocation 0xa0
106: #define at_bitmap 0xb0
107: #define at_symlink 0xc0
108:
109: #define NONAME ""
110: #define ATTR_NORMAL 0
111: #define ATTR_COMPRESSED 1
112: #define ATTR_RESIDENT 2
113: #define ATTR_ENCRYPTED 16384
114: #define ATTR_SPARSE 32768
115:
116: typedef struct run_list {
117: char *start;
118: char *ptr;
119: int svcn;
120: int evcn;
121: int vcn;
122: int cnum0;
123: int cnum;
124: int clen;
125: } RUNL;
126:
127: typedef struct ntfs_mft_record {
128: char mft[MAX_MFT_RECORD_SIZE];
129: char mft2[MAX_MFT_RECORD_SIZE];
130: int attr_type;
131: char *attr_name;
132: int attr_flag;
133: int attr_size;
134: char *attr;
135: int attr_len;
136: RUNL runl;
137: char *attr_list;
138: int attr_list_len;
139: int attr_list_size;
140: int attr_list_off;
141: int attr_inited;
142: char attr_list_buf[2*BLOCK_SIZE];
143: RUNL attr_list_runl;
144: } MFTR;
145:
146:
147: #define index_data ((char *)FSYS_BUF)
148: #define bitmap_data ((__u8 *)(FSYS_BUF+MAX_INDEX_RECORD_SIZE))
149: #define dcdbuf ((__u8 *)index_data)
150: #define dcsbuf (bitmap_data)
151: #define dcend (dcsbuf+DECOMP_SOURCE_BUFFER_SIZE)
152: #define fnbuf ((char *)(bitmap_data+MAX_INDEX_BITMAP_SIZE))
153: #define mmft ((MFTR *)dcend)
154: #define cmft ((MFTR *)(dcend+sizeof(MFTR)))
155: #define mft_run ((RUNL *)(dcend+2*sizeof(MFTR)))
156: #define path_ino ((int *)(dcend+2*sizeof(MFTR)+sizeof(RUNL)))
157: #define cluster16 (path_ino+MAX_DIR_DEPTH)
158: #define index16 cluster16[16]
159: #define blocksize cluster16[17]
160: #define clustersize cluster16[18]
161: #define mft_record_size cluster16[19]
162: #define index_record_size cluster16[20]
163: #define dcvcn cluster16[21]
164: #define dcoff cluster16[22]
165: #define dclen cluster16[23]
166: #define dcrem cluster16[24]
167: #define dcslen cluster16[25]
168: #define dcsptr ((__u8 *)cluster16[26])
169: #define is_ads_completion cluster16[27]
170:
171: static int read_mft_record(int mftno, char *mft, int self);
172: static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl);
173: static int get_next_run(RUNL *runl);
174:
175: static inline int
176: nsubstring (char *s1, char *s2)
177: {
178: while (tolower(*s1) == tolower(*s2))
179: {
180: /* The strings match exactly. */
181: if (! *(s1++))
182: return 0;
183: s2 ++;
184: }
185:
186: /* S1 is a substring of S2. */
187: if (*s1 == 0)
188: return -1;
189:
190: /* S1 isn't a substring. */
191: return 1;
192: }
193:
194: static int fixup_record(char *record, char *magic, int size)
195: {
196: int start, count, offset;
197: __u16 fixup;
198:
199: if(*(int *)record != *(int *)magic)
200: return 0;
201: start=*(__u16 *)(record+4);
202: count=*(__u16 *)(record+6);
203: count--;
204: if(size && blocksize*count != size)
205: return 0;
206: fixup = *(__u16 *)(record+start);
207: start+=2;
208: offset=blocksize-2;
209: while(count--){
210: if(*(__u16 *)(record+offset)!=fixup)
211: return 0;
212: *(__u16 *)(record+offset) = *(__u16 *)(record+start);
213: start+=2;
214: offset+=blocksize;
215: }
216: return 1;
217: }
218:
219: static void rewind_run_list( RUNL *runl) {
220: runl->vcn = runl->svcn;
221: runl->ptr = runl->start;
222: runl->cnum0 = 0;
223: runl->cnum = 0;
224: runl->clen = 0;
225: }
226:
227: static int get_next_run(RUNL *runl){
228: int t, n, v;
229:
230: #ifdef DEBUG_NTFS
231: printf("get_next_run: s=%d e=%d c=%d start=%x ptr=%x\n",
232: runl->svcn, runl->evcn, runl->vcn, runl->start, runl->ptr);
233: #endif
234:
235: runl->vcn += runl->clen;
236: if(runl->vcn > runl->evcn) {
237: return 0;
238: }
239:
240: t = *(runl->ptr)++;
241: n = t&0xf;
242: runl->clen = 0; v = 1;
243: while(n--) {
244: runl->clen += v * *((__u8 *)runl->ptr)++;
245: v <<= 8;
246: }
247: n = (t>>4)&0xf;
248: if(n==0)
249: runl->cnum = 0;
250: else {
251: int c = 0;
252: v = 1;
253: while(n--) {
254: c += v * *((__u8 *)runl->ptr)++;
255: v <<= 8;
256: }
257: if(c & (v>>1)) c -= v;
258: runl->cnum0 += c;
259: runl->cnum = runl->cnum0;
260: }
261: #ifdef DEBUG_NTFS
262: printf("got_next_run: t=%x cluster %x len %x vcn=%x ecn=%x\n",
263: t, runl->cnum, runl->clen, runl->vcn, runl->evcn);
264: #endif
265: return 1;
266: }
267:
268: #ifndef NO_ATTRIBUTE_LIST
269: static void init_run_list(char *attr, int len, RUNL *runl, __u32 *initp) {
270: int allocated;
271:
272: runl->svcn = *(__u32 *)(attr+0x10); /* only support 32 bit */
273: runl->evcn = *(__u32 *)(attr+0x18); /* only support 32 bit */
274: runl->start = attr + *(__u16 *)(attr+0x20);
275: allocated = *(__u32 *)(attr+0x28);
276: if(initp) *initp = *(__u32 *)(attr+0x38);
277: if(!runl->evcn) runl->evcn = (allocated - 1) / clustersize;
278: #ifdef DEBUG_NTFS
279: printf("size %d allocated=%d inited=%d cegin=%x csize=%d vcn=%d-%d\n",
280: /*attr_size*/ *(__u32 *)(attr+0x30),
281: /*allocated*/ *(__u32 *)(attr+0x28),
282: /*attr_inited*/ *(__u32 *)(attr+0x38),
283: /*cengin*/ *(__u16 *)(attr+0x22),
284: /*csize*/ *(__u16 *)(attr+0x40),
285: runl->svcn, runl->evcn);
286: #endif
287: rewind_run_list(runl);
288: }
289: #endif
290:
291:
292: static int find_attribute(char *mft, int type, char *name, char **attr, int *size, int *len, int *flag) {
293: int t, l, r, n, i, namelen;
294: unsigned short *attr_name;
295:
296: n = strlen(name);
297: r = mft_record_size - *(__u16 *)(mft+0x14);
298: mft += *(__u16 *)(mft+0x14);
299: while( (t = *(__s32 *)mft) != -1 ) {
300: l = *(__u32 *)(mft+4);
301: if(l>r) break;
302: #ifdef DEBUG_NTFS
303: printf("type = %x len = %d namelen=%d resident=%d compresed=%d attrno=%d\n",
304: t, l,
305: /*namelen*/ *(mft+9),
306: //name = (__u16 *)(mft + *(__u16 *)(mft+10)),
307: /*resident */ (*(mft+8) == 0),
308: /*compressed*/ *(__u16 *)(mft+12),
309: /*attrno*/ *(__u16 *)(mft+14));
310: #endif
311: namelen = *(mft+9);
312: if(t == type) {
313: #ifndef STAGE1_5
314: #ifndef NO_ALTERNATE_DATASTREAM
315: if(is_ads_completion && type == at_data) {
316: if(namelen && namelen >= n &&
317: (!*(mft+8)/*resident*/ || !*(__u32 *)(attr+0x10)/*svcn==0*/))
318: {
319: for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i < n; i++)
320: if(tolower(name[i]) != tolower(attr_name[i]))
321: break;
322: if(i >= n) {
323: for(; i < namelen; i++)
324: name[i] = attr_name[i];
325: name[i] = '\0';
326: if(print_possibilities > 0)
327: print_possibilities = -print_possibilities;
328: print_a_completion(fnbuf);
329: name[n] = '\0';
330: }
331: }
332: } else
333: #endif
334: #endif
335: if(namelen == n) {
336:
337: for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i<n; i++)
338: if(tolower(name[i]) != tolower(attr_name[i]))
339: break;
340: if(i>=n) {
341: if(flag) *flag = *(__u16 *)(mft+12);
342: if(*(mft+8) == 0) {
343: if(flag) *flag |= ATTR_RESIDENT;
344: #ifdef DEBUG_NTFS
345: printf("resident data at %x size %x indexed=%d\n",
346: /*data*/ *(__u16 *)(mft+0x14),
347: /*attr_size*/ *(__u16 *)(mft+0x10),
348: /*indexed*/ *(__u16 *)(mft+0x16));
349: #endif
350: if(attr) *attr = mft + *(__u16 *)(mft+0x14);
351: if(size) *size = *(__u16 *)(mft+0x10);
352: if(len) *len = *(__u16 *)(mft+0x10);
353: } else {
354: if(attr) *attr = mft;
355: if(size) *size = *(__u32 *)(mft+0x30);
356: if(len) *len = l;
357: }
358: return 1;
359: }
360: }
361: }
362: mft += l;
363: r -= l;
364: }
365: return 0;
366: }
367:
368: #ifndef NO_ATTRIBUTE_LIST
369: static __u32 get_next_attribute_list(MFTR *mftr, int *size) {
370: int l, t, mftno;
371: #ifdef DEBUG_NTFS
372: printf("get_next_attribute_list: type=%x\n",mftr->attr_type);
373: #endif
374: again:
375: while(mftr->attr_list_len>0x14) {
376: t = *(__u32 *)(mftr->attr_list + 0);
377: l = *(__u16 *)(mftr->attr_list + 4);
378: #ifdef DEBUG_NTFS
379: printf("attr_list type=%x len=%x remain=%x\n", t, l, mftr->attr_list_len);
380: #endif
381: if(l==0 || l>mftr->attr_list_len) return 0;
382: mftno = *(__u32 *)(mftr->attr_list + 0x10);
383: mftr->attr_list_len -= l;
384: mftr->attr_list += l;
385: if(t==mftr->attr_type)
386: {
387: #ifdef DEBUG_NTFS
388: printf("attr_list mftno=%x\n", mftno);
389: #endif
390: if(read_mft_record(mftno, mftr->mft2, (mftr==mmft))==0)
391: break;
392: if(find_attribute(mftr->mft2, mftr->attr_type, mftr->attr_name,
393: &mftr->attr, size, &mftr->attr_len, &mftr->attr_flag))
394: return 1;
395: }
396: }
397: #ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST
398: if(mftr->attr_list_off < mftr->attr_list_size) {
399: int len = mftr->attr_list_size - mftr->attr_list_off;
400: if(len > BLOCK_SIZE) len = BLOCK_SIZE;
401:
402: if(mftr->attr_list_len)
403: memmove(mftr->attr_list_buf, mftr->attr_list, mftr->attr_list_len);
404: mftr->attr_list = mftr->attr_list_buf;
405:
406: if(read_attribute( NULL, mftr->attr_list_off,
407: mftr->attr_list_buf + mftr->attr_list_len,
408: len, &mftr->attr_list_runl) != len)
409: {
410: #ifdef DEBUG_NTFS
411: printf("CORRUPT NON-RESIDENT ATTRIBUTE_LIST\n");
412: #endif
413: /* corrupt */
414: errnum = ERR_FSYS_CORRUPT;
415: mftr->attr_list_size = 0;
416: mftr->attr_len = 0;
417: mftr->attr_list = NULL;
418: return 0;
419: }
420:
421: mftr->attr_list_len += len;
422: mftr->attr_list_off += len;
423: goto again;
424: }
425: #endif
426: mftr->attr_list = NULL;
427: return 0;
428: }
429: #endif
430:
431: static int search_attribute( MFTR *mftr, int type, char *name)
432: {
433: #ifdef DEBUG_NTFS
434: printf("searching attribute %x <%s>\n", type, name);
435: #endif
436:
437: mftr->attr_type = type;
438: mftr->attr_name = name;
439: mftr->attr_list = NULL;
440: mftr->attr_list_len = 0;
441: mftr->attr_list_size = 0;
442: mftr->attr_list_off = 0;
443: dcrem = dclen = 0;
444:
445: #ifndef NO_ATTRIBUTE_LIST
446: if(find_attribute(mftr->mft, at_attribute_list, NONAME,
447: &mftr->attr_list, &mftr->attr_list_size,
448: &mftr->attr_list_len, &mftr->attr_list_off)) {
449: if(mftr->attr_list_off&ATTR_RESIDENT) {
450: /* resident at_attribute_list */
451: mftr->attr_list_size = 0;
452: #ifdef DEBUG_NTFS
453: printf("resident attribute_list len=%x\n", mftr->attr_list_len);
454: #endif
455: } else {
456: #ifdef DEBUG_NTFS
457: printf("non-resident attribute_list len=%x size=%x\n",
458: mftr->attr_list_len, mftr->attr_list_size);
459: #endif
460: #ifndef NO_NON_RESIDENT_ATTRIBUTE_LIST
461: init_run_list(mftr->attr_list, mftr->attr_list_len, &mftr->attr_list_runl, NULL);
462: if(get_next_run(&mftr->attr_list_runl)==0 ||
463: mftr->attr_list_runl.cnum==0)
464: mftr->attr_list_size = 0;
465: #endif
466: mftr->attr_list = NULL;
467: mftr->attr_list_len = 0;
468: }
469: }
470: #endif
471:
472: if(find_attribute(mftr->mft, type, name,
473: &mftr->attr, &mftr->attr_size, &mftr->attr_len,
474: &mftr->attr_flag)
475: #ifndef NO_ATTRIBUTE_LIST
476: || get_next_attribute_list(mftr, &mftr->attr_size)
477: #endif
478: )
479: {
480: #ifndef NO_ATTRIBUTE_LIST
481: if(!(mftr->attr_flag&ATTR_RESIDENT)){
482: init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, &mftr->attr_inited);
483: if(mftr->attr_inited > mftr->attr_size)
484: mftr->attr_inited = mftr->attr_size;
485: if(get_next_run(&mftr->runl)==0) {
486: mftr->attr_flag |= ATTR_RESIDENT;
487: mftr->attr_len = 0;
488: }
489: } else
490: mftr->attr_inited = mftr->attr_size;
491: #endif
492:
493: return 1;
494: }
495:
496: mftr->attr_type = 0;
497: return 0;
498: }
499:
500: static int get_run( RUNL *rl, int vcn, int *clp, int *lenp) {
501: if(rl->evcn < vcn)
502: return 0;
503:
504: if(rl->vcn > vcn) {
505: rewind_run_list(rl);
506: get_next_run(rl);
507: }
508:
509: while(rl->vcn+rl->clen <= vcn)
510: {
511: if(get_next_run(rl)==0)
512: return 0;
513: }
514:
515: if(clp) *clp = rl->cnum == 0 ? 0 : rl->cnum + vcn - rl->vcn;
516: if(lenp) *lenp = rl->clen - vcn + rl->vcn;
517: return 1;
518: }
519:
520: static int search_run(MFTR *mftr, int vcn) {
521:
522: if( mftr->attr==NULL && !search_attribute(mftr, mftr->attr_type, mftr->attr_name))
523: return 0;
524:
525: if(mftr->runl.svcn > vcn)
526: search_attribute(mftr, mftr->attr_type, mftr->attr_name);
527:
528: #ifdef NO_ATTRIBUTE_LIST
529: if(mftr->runl.evcn < vcn)
530: return 0;
531: #else
532: while(mftr->runl.evcn < vcn) {
533: if(get_next_attribute_list(mftr, NULL)==0) {
534: mftr->attr = NULL;
535: return 0;
536: }
537: init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, NULL);
538: if(get_next_run(&mftr->runl)==0) {
539: mftr->attr = NULL;
540: return 0;
541: }
542: }
543: #endif
544:
545: return 1;
546: }
547:
548: static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl) {
549: int vcn;
550: int cnum, clen;
551: int done = 0;
552: int n;
553: RUNL *rl;
554:
555: if(!from_rl && (mftr->attr_flag & ATTR_RESIDENT)) {
556: /* resident attribute */
557: if(offset > mftr->attr_len)
558: return 0;
559: if(offset+len > mftr->attr_len)
560: len = mftr->attr_len - offset;
561: memmove( buf, mftr->attr + offset, len);
562: return len;
563: }
564:
565: vcn = offset / clustersize;
566: offset %= clustersize;
567:
568: while(len>0) {
569: if(from_rl)
570: rl = from_rl;
571: else if(search_run(mftr, vcn) == 0)
572: break;
573: else
574: rl = &mftr->runl;
575: if(get_run(rl, vcn, &cnum, &clen) == 0)
576: break;
577: if(cnum==0 && from_rl)
578: break;
579: n = clen * clustersize - offset;
580: if(n > len) n = len;
581: if(cnum==0) {
582: memset( buf, 0, n);
583: } else if(!devread(cnum*(clustersize>>9)+(offset>>9), offset&0x1ff, n, buf))
584: break;
585:
586: buf += n;
587: vcn += (offset+n)/clustersize;
588: done += n;
589: offset = 0;
590: len -= n;
591: }
592: return done;
593: }
594:
595: static int read_mft_record(int mftno, char *mft, int self){
596: #ifdef DEBUG_NTFS
597: printf("Reading MFT record: mftno=%d\n", mftno);
598: #endif
599: if( read_attribute( mmft, mftno * mft_record_size,
600: mft, mft_record_size, self?mft_run:NULL) != mft_record_size)
601: return 0;
602: if(!fixup_record( mft, "FILE", mft_record_size))
603: return 0;
604: return 1;
605: }
606:
607: #ifndef NO_NTFS_DECOMPRESSION
608: static int get_16_cluster(MFTR *mftr, int vcn) {
609: int n = 0, cnum, clen;
610: while(n < 16 && search_run(mftr, vcn) && get_run(&mftr->runl, vcn, &cnum, &clen) && cnum) {
611: if(clen > 16 - n)
612: clen = 16 - n;
613: vcn += clen;
614: while(clen--)
615: cluster16[n++] = cnum++;
616: }
617: cluster16[n] = 0;
618: return n;
619: }
620:
621: static inline int compressed_block_size( unsigned char *src ) {
622: return 3 + (*(__u16 *)src & 0xfff);
623: }
624:
625: static int decompress_block(unsigned char *dest, unsigned char *src) {
626: int head;
627: int copied=0;
628: unsigned char *last;
629: int bits;
630: int tag=0;
631:
632: /* high bit indicates that compression was performed */
633: if(!(*(__u16 *)src & 0x8000)) {
634: memmove(dest,src+2,0x1000);
635: return 0x1000;
636: }
637:
638: if((head = *(__u16 *)src & 0xFFF)==0)
639: /* block is not used */
640: return 0;
641:
642: src += 2;
643: last = src+head;
644: bits = 0;
645:
646: while(src<=last)
647: {
648: if(copied>4096)
649: {
650: #ifdef DEBUG_NTFS
651: printf("decompress error 1\n");
652: #endif
653: errnum = ERR_FSYS_CORRUPT;
654: return 0;
655: }
656: if(!bits){
657: tag=*(__u8 *)src;
658: bits=8;
659: src++;
660: if(src>last)
661: break;
662: }
663: if(tag & 1){
664: int i,len,delta,code,lmask,dshift;
665: code = *(__u16 *)src;
666: src+=2;
667: if(!copied)
668: {
669: #ifdef DEBUG_NTFS
670: printf("decompress error 2\n");
671: #endif
672: errnum = ERR_FSYS_CORRUPT;
673: return 0;
674: }
675: for(i=copied-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1)
676: {
677: lmask >>= 1;
678: dshift--;
679: }
680: delta = code >> dshift;
681: len = (code & lmask) + 3;
682: for(i=0; i<len; i++)
683: {
684: dest[copied]=dest[copied-delta-1];
685: copied++;
686: }
687: } else
688: dest[copied++]=*(__u8 *)src++;
689: tag>>=1;
690: bits--;
691: }
692:
693: return copied;
694: }
695: #endif
696:
697: int ntfs_read(char *buf, int len){
698: int ret;
699: #ifdef STAGE1_5
700: /* stage2 can't be resident/compressed/encrypted files,
701: * but does sparse flag, cause stage2 never sparsed
702: */
703: if((cmft->attr_flag&~ATTR_SPARSE) != ATTR_NORMAL)
704: return 0;
705: disk_read_func = disk_read_hook;
706: ret = read_attribute(cmft, filepos, buf, len, 0);
707: disk_read_func = NULL;
708: filepos += ret;
709: #else
710:
711: #ifndef NO_NTFS_DECOMPRESSION
712: int off;
713: int vcn;
714: int size;
715: int len0;
716: #endif
717:
718: if(len<=0 || filepos >= cmft->attr_size || (cmft->attr_flag&ATTR_ENCRYPTED))
719: return 0;
720:
721: if(filepos+len > cmft->attr_size)
722: len = cmft->attr_size - filepos;
723: if(filepos >= cmft->attr_inited) {
724: #ifdef DEBUG_NTFS
725: printf("reading uninitialized data 1\n");
726: #endif
727: memset(buf, 0, len);
728: return len;
729: } else if(filepos+len > cmft->attr_inited) {
730: len0 = len;
731: len = cmft->attr_inited - filepos;
732: len0 -= len;
733: } else
734: len0 = 0;
735: #ifdef DEBUG_NTFS
736: printf("read filepos=%x filemax=%x inited=%x len=%x len0=%x\n",filepos,filemax,cmft->attr_inited,len,len0);
737: #endif
738:
739: if((cmft->attr_flag&(ATTR_COMPRESSED|ATTR_RESIDENT)) != ATTR_COMPRESSED) {
740: if(cmft->attr_flag==ATTR_NORMAL)
741: disk_read_func = disk_read_hook;
742: ret = read_attribute(cmft, filepos, buf, len, 0);
743: if(cmft->attr_flag==ATTR_NORMAL)
744: disk_read_func = NULL;
745: filepos += ret;
746: if(ret==len && len0) {
747: memset(buf+len, 0, len0);
748: filepos += len0;
749: ret += len0;
750: }
751: return ret;
752: }
753:
754: ret = 0;
755:
756: #ifndef NO_NTFS_DECOMPRESSION
757: /* NTFS don't support compression if cluster size > 4k */
758: if(clustersize > 4096) {
759: errnum = ERR_FSYS_CORRUPT;
760: return 0;
761: }
762:
763: while(len > 0){
764: #ifdef DEBUG_NTFS
765: printf("Reading filepos=%x len=%x\n", filepos, len);
766: #endif
767: if(filepos >= dcoff && filepos < (dcoff+dclen)) {
768: #ifdef DEBUG_NTFS
769: printf("decompress cache %x+%x\n", dcoff, dclen);
770: #endif
771: size = dcoff + dclen - filepos;
772: if(size > len) size = len;
773: memmove( buf, dcdbuf + filepos - dcoff, size);
774: filepos += size;
775: len -= size;
776: ret += size;
777: buf += size;
778: if(len==0) {
779: if(len0) {
780: #ifdef DEBUG_NTFS
781: printf("reading uninitialized data 2\n");
782: #endif
783: memset(buf, 0, len0);
784: filepos += len0;
785: ret += len0;
786: }
787: return ret;
788: }
789: }
790:
791: vcn = filepos / clustersize / 16;
792: vcn *= 16;
793: off = filepos % (16 * clustersize);
794: if( dcvcn != vcn || filepos < dcoff)
795: dcrem = 0;
796:
797: #ifdef DEBUG_NTFS
798: printf("vcn %x off %x dcrem %x\n", vcn, off, dcrem);
799: #endif
800: if(dcrem) {
801: int head;
802:
803: /* reading source */
804: if(dcslen < 2 || compressed_block_size(dcsptr) > dcslen) {
805: if(cluster16[index16]==0) {
806: errnum = ERR_FSYS_CORRUPT;
807: return ret;
808: }
809: if(dcslen)
810: memmove(dcsbuf, dcsptr, dcslen);
811: dcsptr = dcsbuf;
812: while((dcslen+clustersize) < DECOMP_SOURCE_BUFFER_SIZE) {
813: if(cluster16[index16]==0)
814: break;
815: #ifdef DEBUG_NTFS
816: printf("reading dcslen=%x cluster %x\n", dcslen, cluster16[index16]);
817: #endif
818: if(!devread(cluster16[index16]*(clustersize>>9), 0, clustersize, dcsbuf+dcslen))
819: return ret;
820: dcslen += clustersize;
821: index16++;
822: }
823: }
824: /* flush destination */
825: dcoff += dclen;
826: dclen = 0;
827:
828: while(dcrem && dclen < DECOMP_DEST_BUFFER_SIZE &&
829: dcslen >= 2 && (head=compressed_block_size(dcsptr)) <= dcslen) {
830: size = decompress_block(dcdbuf+dclen, dcsptr);
831: if(dcrem>=0x1000 && size!=0x1000) {
832: errnum = ERR_FSYS_CORRUPT;
833: return ret;
834: }
835: dcrem -= size;
836: dclen += size;
837: dcsptr += head;
838: dcslen -= head;
839: }
840: continue;
841: }
842: dclen = dcrem = 0;
843: #ifdef DEBUG_NTFS
844: printf("get next 16 clusters\n");
845: #endif
846: switch(get_16_cluster(cmft, vcn)) {
847: case 0:
848: #ifdef DEBUG_NTFS
849: printf("sparse\n");
850: #endif
851: /* sparse */
852: size = 16 * clustersize - off;
853: if( len < size )
854: size = len;
855: #ifndef STAGE1_5
856: memset( buf, 0, size);
857: #endif
858: filepos += size;
859: len -= size;
860: ret += size;
861: buf += size;
862: break;
863:
864: case 16:
865: #ifdef DEBUG_NTFS
866: printf("uncompressed\n");
867: #endif
868: /* uncompressed */
869: index16 = off / clustersize;
870: off %= clustersize;
871: while(index16 < 16) {
872: size = clustersize - off;
873: if( len < size )
874: size = len;
875: if(!devread(cluster16[index16]*(clustersize>>9)+(off>>9), off&0x1ff, size, buf))
876: return ret;
877: filepos += size;
878: len -= size;
879: ret += size;
880: if(len==0)
881: return ret;
882: off = 0;
883: buf += size;
884: index16++;
885: }
886: break;
887:
888: default:
889: #ifdef DEBUG_NTFS
890: printf("compressed\n");
891: #endif
892: index16 = 0;
893: dcvcn = vcn;
894: dcoff = vcn * clustersize;
895: dcrem = cmft->attr_inited - dcoff;
896: if(dcrem > 16 * clustersize)
897: dcrem = 16 * clustersize;
898: dcsptr = dcsbuf;
899: dcslen = 0;
900: }
901: }
902: if(len0) {
903: #ifdef DEBUG_NTFS
904: printf("reading uninitialized data 3\n");
905: #endif
906: memset(buf, 0, len0);
907: filepos += len0;
908: ret += len0;
909: }
910: #else
911: errnum = FSYS_CORRUPT;
912: #endif /*NO_NTFS_DECOMPRESSION*/
913: #endif /*STAGE1_5*/
914: return ret;
915: }
916:
917: int ntfs_mount (void)
918: {
919: char *sb = (char *)FSYS_BUF;
920: int mft_record;
921: int spc;
922:
923: if (((current_drive & 0x80) || (current_slice != 0))
924: && (current_slice != /*PC_SLICE_TYPE_NTFS*/7)
925: && (current_slice != /*PC_SLICE_TYPE_NTFS*/0x17))
926: return 0;
927:
928: if (!devread (0, 0, 512, (char *) FSYS_BUF))
929: return 0; /* Cannot read superblock */
930:
931: if(sb[3]!='N' || sb[4]!='T' || sb[5]!='F' || sb[6]!='S')
932: return 0;
933: blocksize = *(__u16 *)(sb+0xb);
934: spc = *(unsigned char *)(sb+0xd);
935: clustersize = spc * blocksize;
936: mft_record_size = *(char *)(sb+0x40);
937: index_record_size = *(char *)(sb+0x44);
938: if(mft_record_size>0)
939: mft_record_size *= clustersize;
940: else
941: mft_record_size = 1 << (-mft_record_size);
942:
943: index_record_size *= clustersize;
944: mft_record = *(__u32 *)(sb+0x30); /* only support 32 bit */
945: spc = clustersize / 512;
946:
947: if(mft_record_size > MAX_MFT_RECORD_SIZE || index_record_size > MAX_INDEX_RECORD_SIZE) {
948: /* only support 1k MFT record, 4k INDEX record */
949: return 0;
950: }
951:
952: #ifdef DEBUG_NTFS
953: printf("spc=%x mft_record=%x:%x\n", spc, *(__s64 *)(sb+0x30));
954: #endif
955:
956: if (!devread (mft_record*spc, 0, mft_record_size, mmft->mft))
957: return 0; /* Cannot read superblock */
958:
959: if(!fixup_record( mmft->mft, "FILE", mft_record_size))
960: return 0;
961:
962: #ifndef NO_ALTERNATE_DATASTREAM
963: is_ads_completion = 0;
964: #endif
965: if(!search_attribute(mmft, at_data, NONAME)) return 0;
966:
967: *mft_run = mmft->runl;
968:
969: *path_ino = FILE_ROOT;
970:
971: return 1;
972: }
973:
974: int
975: ntfs_dir (char *dirname)
976: {
977: char *rest, ch;
978: int namelen;
979: int depth = 0;
980: int chk_sfn = 1;
981: int flag = 0;
982: int record_offset;
983: int my_index_record_size;
984: unsigned char *index_entry = 0, *entry, *index_end;
985: int i;
986:
987: /* main loop to find desired directory entry */
988: loop:
989:
990: #ifdef DEBUG_NTFS
991: printf("dirname=%s\n", dirname);
992: #endif
993: if(!read_mft_record(path_ino[depth], cmft->mft, 0))
994: {
995: #ifdef DEBUG_NTFS
996: printf("MFT error 1\n");
997: #endif
998: errnum = ERR_FSYS_CORRUPT;
999: return 0;
1000: }
1001:
1002: /* if we have a real file (and we're not just printing possibilities),
1003: then this is where we want to exit */
1004:
1005: if (!*dirname || isspace (*dirname) || *dirname==':')
1006: {
1007: #ifndef STAGE1_5
1008: #ifndef NO_ALTERNATE_DATASTREAM
1009: if (*dirname==':' && print_possibilities) {
1010: char *tmp;
1011:
1012: /* preparing ADS name completion */
1013: for(tmp = dirname; *tmp != '/'; tmp--);
1014: for(tmp++, rest=fnbuf; *tmp && !isspace(*tmp); *rest++ = *tmp++)
1015: if(*tmp==':') dirname = rest;
1016: *rest++ = '\0';
1017:
1018: is_ads_completion = 1;
1019: search_attribute(cmft, at_data, dirname+1);
1020: is_ads_completion = 0;
1021:
1022: if(errnum==0) {
1023: if(print_possibilities < 0)
1024: return 1;
1025: errnum = ERR_FILE_NOT_FOUND;
1026: }
1027: return 0;
1028: }
1029: #endif
1030: #endif
1031:
1032: if (*dirname==':') dirname++;
1033: for (rest = dirname; (ch = *rest) && !isspace (ch); rest++);
1034: *rest = 0;
1035:
1036: #ifdef DEBUG_NTFS
1037: printf("got file: search at_data\n");
1038: #endif
1039:
1040: if (!search_attribute(cmft, at_data, dirname)) {
1041: errnum = *(dirname-1)==':'?ERR_FILE_NOT_FOUND:ERR_BAD_FILETYPE;
1042: *rest = ch;
1043: return 0;
1044: }
1045: *rest = ch;
1046:
1047: filemax = cmft->attr_size;
1048: #ifdef DEBUG_NTFS
1049: printf("filemax=%x\n", filemax);
1050: #endif
1051: return 1;
1052: }
1053:
1054: if(depth >= (MAX_DIR_DEPTH-1)) {
1055: errnum = ERR_FSYS_CORRUPT;
1056: return 0;
1057: }
1058:
1059: /* continue with the file/directory name interpretation */
1060:
1061: while (*dirname == '/')
1062: dirname++;
1063:
1064: for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/' && ch != ':'; rest++);
1065:
1066: *rest = 0;
1067:
1068: if (!search_attribute(cmft, at_index_root, "$I30"))
1069: {
1070: errnum = ERR_BAD_FILETYPE;
1071: return 0;
1072: }
1073:
1074: read_attribute(cmft, 0, fnbuf, 16, 0);
1075: my_index_record_size = *(__u32 *)(fnbuf+8);
1076:
1077: if(my_index_record_size > MAX_INDEX_RECORD_SIZE) {
1078: errnum = ERR_FSYS_CORRUPT;
1079: return 0;
1080: }
1081:
1082: #ifdef DEBUG_NTFS
1083: printf("index_record_size=%x\n", my_index_record_size);
1084: #endif
1085:
1086: if(cmft->attr_size > MAX_INDEX_RECORD_SIZE) {
1087: errnum = ERR_FSYS_CORRUPT;
1088: return 0;
1089: }
1090: read_attribute(cmft, 0, index_data, cmft->attr_size, 0);
1091: index_end = index_data + cmft->attr_size;
1092: index_entry = index_data + 0x20;
1093: record_offset = -1;
1094:
1095: #ifndef STAGE1_5
1096: if (print_possibilities && ch != '/' && ch != ':' && !*dirname)
1097: {
1098: print_possibilities = -print_possibilities;
1099: /* fake '.' for empty directory */
1100: print_a_completion (".");
1101: }
1102: #endif
1103:
1104: if (search_attribute(cmft, at_bitmap, "$I30")) {
1105: if(cmft->attr_size > MAX_INDEX_BITMAP_SIZE) {
1106: errnum = ERR_FSYS_CORRUPT;
1107: return 0;
1108: }
1109:
1110: read_attribute(cmft, 0, bitmap_data, cmft->attr_size, 0);
1111:
1112: if (search_attribute(cmft, at_index_allocation, "$I30")==0) {
1113: errnum = ERR_FSYS_CORRUPT;
1114: return 0;
1115: }
1116:
1117: for(record_offset = 0; record_offset*my_index_record_size<cmft->attr_size; record_offset++){
1118: int bit = 1 << (record_offset&3);
1119: int byte = record_offset>>3;
1120: #ifdef DEBUG_NTFS
1121: printf("record_offset=%x\n", record_offset);
1122: #endif
1123: if((bitmap_data[byte]&bit))
1124: break;
1125: }
1126:
1127: if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1;
1128: }
1129:
1130: do
1131: {
1132: entry = index_entry; index_entry += *(__u16 *)(entry+8);
1133: if(entry+0x50>=index_entry||entry>=index_end||
1134: index_entry>=index_end||(entry[0x12]&2)){
1135: if(record_offset < 0 ||
1136: !read_attribute(cmft, record_offset*my_index_record_size, index_data, my_index_record_size, 0)){
1137: if (!errnum)
1138: {
1139: if (print_possibilities < 0)
1140: {
1141: #if 0
1142: putchar ('\n');
1143: #endif
1144: return 1;
1145: }
1146:
1147: errnum = ERR_FILE_NOT_FOUND;
1148: *rest = ch;
1149: }
1150:
1151: return 0;
1152: }
1153: if(!fixup_record( index_data, "INDX", my_index_record_size))
1154: {
1155: #ifdef DEBUG_NTFS
1156: printf("index error\n");
1157: #endif
1158: errnum = ERR_FSYS_CORRUPT;
1159: return 0;
1160: }
1161: entry = index_data + 0x18 + *(__u16 *)(index_data+0x18);
1162: index_entry = entry + *(__u16 *)(entry+8);
1163: index_end = index_data + my_index_record_size - 0x52;
1164: for(record_offset++; record_offset*my_index_record_size<cmft->attr_size; record_offset++){
1165: int bit = 1 << (record_offset&3);
1166: int byte = record_offset>>3;
1167: if((bitmap_data[byte]&bit)) break;
1168: }
1169: if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1;
1170: #ifdef DEBUG_NTFS
1171: printf("record_offset=%x\n", record_offset);
1172: #endif
1173: }
1174: flag = entry[0x51];
1175: path_ino[depth+1] = *(__u32 *)entry;
1176: if(path_ino[depth+1] < 16)
1177: continue;
1178: namelen = entry[0x50];
1179: //if(index_data[0x48]&2) printf("hidden file\n");
1180: #ifndef STAGE1_5
1181: /* skip short file name */
1182: if( flag == 2 && print_possibilities && ch != '/' && ch != ':' )
1183: continue;
1184: #endif
1185:
1186: for( i = 0, entry+=0x52; i < namelen; i++, entry+=2 )
1187: {
1188: int c = *(__u16 *)entry;
1189: if(c==' '||c>=0x100)
1190: fnbuf[i] = '_';
1191: else
1192: fnbuf[i] = c;
1193: }
1194: fnbuf[namelen] = 0;
1195: #ifdef DEBUG_NTFS
1196: printf("FLAG: %d NAME: %s inum=%d\n", flag,fnbuf,path_ino[depth+1]);
1197: #endif
1198:
1199: //uncntrl(fnbuf);
1200:
1201: chk_sfn = nsubstring(dirname,fnbuf);
1202: #ifndef STAGE1_5
1203: if (print_possibilities && ch != '/' && ch != ':'
1204: && (!*dirname || chk_sfn <= 0))
1205: {
1206: if (print_possibilities > 0)
1207: print_possibilities = -print_possibilities;
1208: print_a_completion (fnbuf);
1209: }
1210: #endif /* STAGE1_5 */
1211: }
1212: while (chk_sfn != 0 ||
1213: (print_possibilities && ch != '/' && ch != ':'));
1214:
1215: *(dirname = rest) = ch;
1216:
1217: depth++;
1218:
1219: /* go back to main loop at top of function */
1220: goto loop;
1221: }
1222:
1223: #ifdef DEBUG_NTFS
1224: int dump_block(char *msg, char *buf, int size){
1225: int l = (size+15)/16;
1226: int off;
1227: int i, j;
1228: int c;
1229: printf("----- %s -----\n", msg);
1230: for( i = 0, off = 0; i < l; i++, off+=16)
1231: {
1232: if(off<16)
1233: printf("000%x:", off);
1234: else if(off<256)
1235: printf("00%x:", off);
1236: else
1237: printf("0%x:", off);
1238: for(j=0;j<16;j++)
1239: {
1240: c = buf[off+j]&0xff;
1241: if( c >= 16 )
1242: printf("%c%x",j==8?'-':' ',c);
1243: else
1244: printf("%c0%x",j==8?'-':' ',c);
1245: }
1246: printf(" ");
1247: for(j=0;j<16;j++) {
1248: char c = buf[off+j];
1249: printf("%c",c<' '||c>='\x7f'?'.':c);
1250: }
1251: printf("\n");
1252: }
1253: }
1254: #endif
1255: #endif /* FSYS_NTFS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.