3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999 Free Software Foundation, Inc.
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.
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.
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,
23 * Samuel Leo <samuel@_.remove.me._szonline.net>
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
36 //#define DEBUG_NTFS 1
39 #define NO_ATTRIBUTE_LIST 1
40 totally disable at_attribute_list support,
41 if no compressed/fragment file and MFT,
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
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
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
68 /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
71 /* include/linux/fs.h */
72 #define BLOCK_SIZE 512
75 #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
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;
88 #define FILE_MFTMIRR 1
89 #define FILE_LOGFILE 2
91 #define FILE_ATTRDEF 4
95 #define FILE_BADCLUS 8
97 #define FILE_UPCASE 10
99 #define at_standard_information 0x10
100 #define at_attribute_list 0x20
101 #define at_filename 0x30
102 #define at_security_descriptor 0x50
104 #define at_index_root 0x90
105 #define at_index_allocation 0xa0
106 #define at_bitmap 0xb0
107 #define at_symlink 0xc0
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
116 typedef struct run_list {
127 typedef struct ntfs_mft_record {
128 char mft[MAX_MFT_RECORD_SIZE];
129 char mft2[MAX_MFT_RECORD_SIZE];
142 char attr_list_buf[2*BLOCK_SIZE];
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]
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);
176 nsubstring (char *s1, char *s2)
178 while (tolower(*s1) == tolower(*s2))
180 /* The strings match exactly. */
186 /* S1 is a substring of S2. */
190 /* S1 isn't a substring. */
194 static int fixup_record(char *record, char *magic, int size)
196 int start, count, offset;
199 if(*(int *)record != *(int *)magic)
201 start=*(__u16 *)(record+4);
202 count=*(__u16 *)(record+6);
204 if(size && blocksize*count != size)
206 fixup = *(__u16 *)(record+start);
210 if(*(__u16 *)(record+offset)!=fixup)
212 *(__u16 *)(record+offset) = *(__u16 *)(record+start);
219 static void rewind_run_list( RUNL *runl) {
220 runl->vcn = runl->svcn;
221 runl->ptr = runl->start;
227 static int get_next_run(RUNL *runl){
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);
235 runl->vcn += runl->clen;
236 if(runl->vcn > runl->evcn) {
242 runl->clen = 0; v = 1;
244 runl->clen += v * *((__u8 *)runl->ptr)++;
254 c += v * *((__u8 *)runl->ptr)++;
257 if(c & (v>>1)) c -= v;
259 runl->cnum = runl->cnum0;
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);
268 #ifndef NO_ATTRIBUTE_LIST
269 static void init_run_list(char *attr, int len, RUNL *runl, __u32 *initp) {
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;
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);
287 rewind_run_list(runl);
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;
297 r = mft_record_size - *(__u16 *)(mft+0x14);
298 mft += *(__u16 *)(mft+0x14);
299 while( (t = *(__s32 *)mft) != -1 ) {
300 l = *(__u32 *)(mft+4);
303 printf("type = %x len = %d namelen=%d resident=%d compresed=%d attrno=%d\n",
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));
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*/))
319 for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i < n; i++)
320 if(tolower(name[i]) != tolower(attr_name[i]))
323 for(; i < namelen; i++)
324 name[i] = attr_name[i];
326 if(print_possibilities > 0)
327 print_possibilities = -print_possibilities;
328 print_a_completion(fnbuf);
337 for(i=0, attr_name=(__u16 *)(mft + *(__u16 *)(mft+10)); i<n; i++)
338 if(tolower(name[i]) != tolower(attr_name[i]))
341 if(flag) *flag = *(__u16 *)(mft+12);
343 if(flag) *flag |= ATTR_RESIDENT;
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));
350 if(attr) *attr = mft + *(__u16 *)(mft+0x14);
351 if(size) *size = *(__u16 *)(mft+0x10);
352 if(len) *len = *(__u16 *)(mft+0x10);
354 if(attr) *attr = mft;
355 if(size) *size = *(__u32 *)(mft+0x30);
368 #ifndef NO_ATTRIBUTE_LIST
369 static __u32 get_next_attribute_list(MFTR *mftr, int *size) {
372 printf("get_next_attribute_list: type=%x\n",mftr->attr_type);
375 while(mftr->attr_list_len>0x14) {
376 t = *(__u32 *)(mftr->attr_list + 0);
377 l = *(__u16 *)(mftr->attr_list + 4);
379 printf("attr_list type=%x len=%x remain=%x\n", t, l, mftr->attr_list_len);
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)
388 printf("attr_list mftno=%x\n", mftno);
390 if(read_mft_record(mftno, mftr->mft2, (mftr==mmft))==0)
392 if(find_attribute(mftr->mft2, mftr->attr_type, mftr->attr_name,
393 &mftr->attr, size, &mftr->attr_len, &mftr->attr_flag))
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;
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;
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)
411 printf("CORRUPT NON-RESIDENT ATTRIBUTE_LIST\n");
414 errnum = ERR_FSYS_CORRUPT;
415 mftr->attr_list_size = 0;
417 mftr->attr_list = NULL;
421 mftr->attr_list_len += len;
422 mftr->attr_list_off += len;
426 mftr->attr_list = NULL;
431 static int search_attribute( MFTR *mftr, int type, char *name)
434 printf("searching attribute %x <%s>\n", type, name);
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;
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;
453 printf("resident attribute_list len=%x\n", mftr->attr_list_len);
457 printf("non-resident attribute_list len=%x size=%x\n",
458 mftr->attr_list_len, mftr->attr_list_size);
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;
466 mftr->attr_list = NULL;
467 mftr->attr_list_len = 0;
472 if(find_attribute(mftr->mft, type, name,
473 &mftr->attr, &mftr->attr_size, &mftr->attr_len,
475 #ifndef NO_ATTRIBUTE_LIST
476 || get_next_attribute_list(mftr, &mftr->attr_size)
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;
490 mftr->attr_inited = mftr->attr_size;
500 static int get_run( RUNL *rl, int vcn, int *clp, int *lenp) {
509 while(rl->vcn+rl->clen <= vcn)
511 if(get_next_run(rl)==0)
515 if(clp) *clp = rl->cnum == 0 ? 0 : rl->cnum + vcn - rl->vcn;
516 if(lenp) *lenp = rl->clen - vcn + rl->vcn;
520 static int search_run(MFTR *mftr, int vcn) {
522 if( mftr->attr==NULL && !search_attribute(mftr, mftr->attr_type, mftr->attr_name))
525 if(mftr->runl.svcn > vcn)
526 search_attribute(mftr, mftr->attr_type, mftr->attr_name);
528 #ifdef NO_ATTRIBUTE_LIST
529 if(mftr->runl.evcn < vcn)
532 while(mftr->runl.evcn < vcn) {
533 if(get_next_attribute_list(mftr, NULL)==0) {
537 init_run_list(mftr->attr, mftr->attr_len, &mftr->runl, NULL);
538 if(get_next_run(&mftr->runl)==0) {
548 static int read_attribute(MFTR *mftr, int offset, char *buf, int len, RUNL *from_rl) {
555 if(!from_rl && (mftr->attr_flag & ATTR_RESIDENT)) {
556 /* resident attribute */
557 if(offset > mftr->attr_len)
559 if(offset+len > mftr->attr_len)
560 len = mftr->attr_len - offset;
561 memmove( buf, mftr->attr + offset, len);
565 vcn = offset / clustersize;
566 offset %= clustersize;
571 else if(search_run(mftr, vcn) == 0)
575 if(get_run(rl, vcn, &cnum, &clen) == 0)
577 if(cnum==0 && from_rl)
579 n = clen * clustersize - offset;
583 } else if(!devread(cnum*(clustersize>>9)+(offset>>9), offset&0x1ff, n, buf))
587 vcn += (offset+n)/clustersize;
595 static int read_mft_record(int mftno, char *mft, int self){
597 printf("Reading MFT record: mftno=%d\n", mftno);
599 if( read_attribute( mmft, mftno * mft_record_size,
600 mft, mft_record_size, self?mft_run:NULL) != mft_record_size)
602 if(!fixup_record( mft, "FILE", mft_record_size))
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) {
615 cluster16[n++] = cnum++;
621 static inline int compressed_block_size( unsigned char *src ) {
622 return 3 + (*(__u16 *)src & 0xfff);
625 static int decompress_block(unsigned char *dest, unsigned char *src) {
632 /* high bit indicates that compression was performed */
633 if(!(*(__u16 *)src & 0x8000)) {
634 memmove(dest,src+2,0x1000);
638 if((head = *(__u16 *)src & 0xFFF)==0)
639 /* block is not used */
651 printf("decompress error 1\n");
653 errnum = ERR_FSYS_CORRUPT;
664 int i,len,delta,code,lmask,dshift;
665 code = *(__u16 *)src;
670 printf("decompress error 2\n");
672 errnum = ERR_FSYS_CORRUPT;
675 for(i=copied-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1)
680 delta = code >> dshift;
681 len = (code & lmask) + 3;
684 dest[copied]=dest[copied-delta-1];
688 dest[copied++]=*(__u8 *)src++;
697 int ntfs_read(char *buf, int len){
700 /* stage2 can't be resident/compressed/encrypted files,
701 * but does sparse flag, cause stage2 never sparsed
703 if((cmft->attr_flag&~ATTR_SPARSE) != ATTR_NORMAL)
705 disk_read_func = disk_read_hook;
706 ret = read_attribute(cmft, filepos, buf, len, 0);
707 disk_read_func = NULL;
711 #ifndef NO_NTFS_DECOMPRESSION
718 if(len<=0 || filepos >= cmft->attr_size || (cmft->attr_flag&ATTR_ENCRYPTED))
721 if(filepos+len > cmft->attr_size)
722 len = cmft->attr_size - filepos;
723 if(filepos >= cmft->attr_inited) {
725 printf("reading uninitialized data 1\n");
729 } else if(filepos+len > cmft->attr_inited) {
731 len = cmft->attr_inited - filepos;
736 printf("read filepos=%x filemax=%x inited=%x len=%x len0=%x\n",filepos,filemax,cmft->attr_inited,len,len0);
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;
746 if(ret==len && len0) {
747 memset(buf+len, 0, len0);
756 #ifndef NO_NTFS_DECOMPRESSION
757 /* NTFS don't support compression if cluster size > 4k */
758 if(clustersize > 4096) {
759 errnum = ERR_FSYS_CORRUPT;
765 printf("Reading filepos=%x len=%x\n", filepos, len);
767 if(filepos >= dcoff && filepos < (dcoff+dclen)) {
769 printf("decompress cache %x+%x\n", dcoff, dclen);
771 size = dcoff + dclen - filepos;
772 if(size > len) size = len;
773 memmove( buf, dcdbuf + filepos - dcoff, size);
781 printf("reading uninitialized data 2\n");
783 memset(buf, 0, len0);
791 vcn = filepos / clustersize / 16;
793 off = filepos % (16 * clustersize);
794 if( dcvcn != vcn || filepos < dcoff)
798 printf("vcn %x off %x dcrem %x\n", vcn, off, dcrem);
804 if(dcslen < 2 || compressed_block_size(dcsptr) > dcslen) {
805 if(cluster16[index16]==0) {
806 errnum = ERR_FSYS_CORRUPT;
810 memmove(dcsbuf, dcsptr, dcslen);
812 while((dcslen+clustersize) < DECOMP_SOURCE_BUFFER_SIZE) {
813 if(cluster16[index16]==0)
816 printf("reading dcslen=%x cluster %x\n", dcslen, cluster16[index16]);
818 if(!devread(cluster16[index16]*(clustersize>>9), 0, clustersize, dcsbuf+dcslen))
820 dcslen += clustersize;
824 /* flush destination */
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;
844 printf("get next 16 clusters\n");
846 switch(get_16_cluster(cmft, vcn)) {
852 size = 16 * clustersize - off;
856 memset( buf, 0, size);
866 printf("uncompressed\n");
869 index16 = off / clustersize;
871 while(index16 < 16) {
872 size = clustersize - off;
875 if(!devread(cluster16[index16]*(clustersize>>9)+(off>>9), off&0x1ff, size, buf))
890 printf("compressed\n");
894 dcoff = vcn * clustersize;
895 dcrem = cmft->attr_inited - dcoff;
896 if(dcrem > 16 * clustersize)
897 dcrem = 16 * clustersize;
904 printf("reading uninitialized data 3\n");
906 memset(buf, 0, len0);
911 errnum = FSYS_CORRUPT;
912 #endif /*NO_NTFS_DECOMPRESSION*/
917 int ntfs_mount (void)
919 char *sb = (char *)FSYS_BUF;
923 if (((current_drive & 0x80) || (current_slice != 0))
924 && (current_slice != /*PC_SLICE_TYPE_NTFS*/7)
925 && (current_slice != /*PC_SLICE_TYPE_NTFS*/0x17))
928 if (!devread (0, 0, 512, (char *) FSYS_BUF))
929 return 0; /* Cannot read superblock */
931 if(sb[3]!='N' || sb[4]!='T' || sb[5]!='F' || sb[6]!='S')
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;
941 mft_record_size = 1 << (-mft_record_size);
943 index_record_size *= clustersize;
944 mft_record = *(__u32 *)(sb+0x30); /* only support 32 bit */
945 spc = clustersize / 512;
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 */
953 printf("spc=%x mft_record=%x:%x\n", spc, *(__s64 *)(sb+0x30));
956 if (!devread (mft_record*spc, 0, mft_record_size, mmft->mft))
957 return 0; /* Cannot read superblock */
959 if(!fixup_record( mmft->mft, "FILE", mft_record_size))
962 #ifndef NO_ALTERNATE_DATASTREAM
963 is_ads_completion = 0;
965 if(!search_attribute(mmft, at_data, NONAME)) return 0;
967 *mft_run = mmft->runl;
969 *path_ino = FILE_ROOT;
975 ntfs_dir (char *dirname)
983 int my_index_record_size;
984 unsigned char *index_entry = 0, *entry, *index_end;
987 /* main loop to find desired directory entry */
991 printf("dirname=%s\n", dirname);
993 if(!read_mft_record(path_ino[depth], cmft->mft, 0))
996 printf("MFT error 1\n");
998 errnum = ERR_FSYS_CORRUPT;
1002 /* if we have a real file (and we're not just printing possibilities),
1003 then this is where we want to exit */
1005 if (!*dirname || isspace (*dirname) || *dirname==':')
1008 #ifndef NO_ALTERNATE_DATASTREAM
1009 if (*dirname==':' && print_possibilities) {
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;
1018 is_ads_completion = 1;
1019 search_attribute(cmft, at_data, dirname+1);
1020 is_ads_completion = 0;
1023 if(print_possibilities < 0)
1025 errnum = ERR_FILE_NOT_FOUND;
1032 if (*dirname==':') dirname++;
1033 for (rest = dirname; (ch = *rest) && !isspace (ch); rest++);
1037 printf("got file: search at_data\n");
1040 if (!search_attribute(cmft, at_data, dirname)) {
1041 errnum = *(dirname-1)==':'?ERR_FILE_NOT_FOUND:ERR_BAD_FILETYPE;
1047 filemax = cmft->attr_size;
1049 printf("filemax=%x\n", filemax);
1054 if(depth >= (MAX_DIR_DEPTH-1)) {
1055 errnum = ERR_FSYS_CORRUPT;
1059 /* continue with the file/directory name interpretation */
1061 while (*dirname == '/')
1064 for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/' && ch != ':'; rest++);
1068 if (!search_attribute(cmft, at_index_root, "$I30"))
1070 errnum = ERR_BAD_FILETYPE;
1074 read_attribute(cmft, 0, fnbuf, 16, 0);
1075 my_index_record_size = *(__u32 *)(fnbuf+8);
1077 if(my_index_record_size > MAX_INDEX_RECORD_SIZE) {
1078 errnum = ERR_FSYS_CORRUPT;
1083 printf("index_record_size=%x\n", my_index_record_size);
1086 if(cmft->attr_size > MAX_INDEX_RECORD_SIZE) {
1087 errnum = ERR_FSYS_CORRUPT;
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;
1096 if (print_possibilities && ch != '/' && ch != ':' && !*dirname)
1098 print_possibilities = -print_possibilities;
1099 /* fake '.' for empty directory */
1100 print_a_completion (".");
1104 if (search_attribute(cmft, at_bitmap, "$I30")) {
1105 if(cmft->attr_size > MAX_INDEX_BITMAP_SIZE) {
1106 errnum = ERR_FSYS_CORRUPT;
1110 read_attribute(cmft, 0, bitmap_data, cmft->attr_size, 0);
1112 if (search_attribute(cmft, at_index_allocation, "$I30")==0) {
1113 errnum = ERR_FSYS_CORRUPT;
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;
1121 printf("record_offset=%x\n", record_offset);
1123 if((bitmap_data[byte]&bit))
1127 if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1;
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)){
1139 if (print_possibilities < 0)
1147 errnum = ERR_FILE_NOT_FOUND;
1153 if(!fixup_record( index_data, "INDX", my_index_record_size))
1156 printf("index error\n");
1158 errnum = ERR_FSYS_CORRUPT;
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;
1169 if(record_offset*my_index_record_size>=cmft->attr_size) record_offset = -1;
1171 printf("record_offset=%x\n", record_offset);
1175 path_ino[depth+1] = *(__u32 *)entry;
1176 if(path_ino[depth+1] < 16)
1178 namelen = entry[0x50];
1179 //if(index_data[0x48]&2) printf("hidden file\n");
1181 /* skip short file name */
1182 if( flag == 2 && print_possibilities && ch != '/' && ch != ':' )
1186 for( i = 0, entry+=0x52; i < namelen; i++, entry+=2 )
1188 int c = *(__u16 *)entry;
1189 if(c==' '||c>=0x100)
1196 printf("FLAG: %d NAME: %s inum=%d\n", flag,fnbuf,path_ino[depth+1]);
1201 chk_sfn = nsubstring(dirname,fnbuf);
1203 if (print_possibilities && ch != '/' && ch != ':'
1204 && (!*dirname || chk_sfn <= 0))
1206 if (print_possibilities > 0)
1207 print_possibilities = -print_possibilities;
1208 print_a_completion (fnbuf);
1210 #endif /* STAGE1_5 */
1212 while (chk_sfn != 0 ||
1213 (print_possibilities && ch != '/' && ch != ':'));
1215 *(dirname = rest) = ch;
1219 /* go back to main loop at top of function */
1224 int dump_block(char *msg, char *buf, int size){
1225 int l = (size+15)/16;
1229 printf("----- %s -----\n", msg);
1230 for( i = 0, off = 0; i < l; i++, off+=16)
1233 printf("000%x:", off);
1235 printf("00%x:", off);
1237 printf("0%x:", off);
1240 c = buf[off+j]&0xff;
1242 printf("%c%x",j==8?'-':' ',c);
1244 printf("%c0%x",j==8?'-':' ',c);
1248 char c = buf[off+j];
1249 printf("%c",c<' '||c>='\x7f'?'.':c);
1255 #endif /* FSYS_NTFS */