fsys_ntfs.c
来自「grub4dos-0.4.4-2008- 08-src.zip」· C语言 代码 · 共 1,445 行 · 第 1/3 页
C
1,445 行
/* * NTFS file system driver for GRUB * * Copyright (C) 2007 Bean (bean123@126.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * Limitations: * 1. Don't support >1K MFT record size, >4K INDEX record size * 2. Don't support encrypted file * 3. Don't support >4K non-resident attribute list and $BITMAP * */#ifdef FSYS_NTFS#include "shared.h"#include "filesys.h"//#define NTFS_DEBUG 1#ifdef FS_UTIL#include "fsutil.h"#endif#define FILE_MFT 0#define FILE_MFTMIRR 1#define FILE_LOGFILE 2#define FILE_VOLUME 3#define FILE_ATTRDEF 4#define FILE_ROOT 5#define FILE_BITMAP 6#define FILE_BOOT 7#define FILE_BADCLUS 8#define FILE_QUOTA 9#define FILE_UPCASE 10#define AT_STANDARD_INFORMATION 0x10#define AT_ATTRIBUTE_LIST 0x20#define AT_FILENAME 0x30#define AT_OBJECT_ID 0x40#define AT_SECURITY_DESCRIPTOR 0x50#define AT_VOLUME_NAME 0x60#define AT_VOLUME_INFORMATION 0x70#define AT_DATA 0x80#define AT_INDEX_ROOT 0x90#define AT_INDEX_ALLOCATION 0xA0#define AT_BITMAP 0xB0#define AT_SYMLINK 0xC0#define AT_EA_INFORMATION 0xD0#define AT_EA 0xE0#define ATTR_READ_ONLY 0x1#define ATTR_HIDDEN 0x2#define ATTR_SYSTEM 0x4#define ATTR_ARCHIVE 0x20#define ATTR_DEVICE 0x40#define ATTR_NORMAL 0x80#define ATTR_TEMPORARY 0x100#define ATTR_SPARSE 0x200#define ATTR_REPARSE 0x400#define ATTR_COMPRESSED 0x800#define ATTR_OFFLINE 0x1000#define ATTR_NOT_INDEXED 0x2000#define ATTR_ENCRYPTED 0x4000#define ATTR_DIRECTORY 0x10000000#define ATTR_INDEX_VIEW 0x20000000#define FLAG_COMPRESSED 1#define FLAG_ENCRYPTED 0x4000#define FLAG_SPARSE 0x8000#define BLK_SHR 9#define MAX_MFT (1024 >> BLK_SHR)#define MAX_IDX (16384 >> BLK_SHR)#define valueat(buf,ofs,type) *((type*)(((char*)buf)+ofs))#define AF_ALST 1#define AF_GPOS 2#define RF_COMP 1#define RF_CBLK 2#define RF_BLNK 4#define set_aflag(a,b) if (b) attr_flg|=(a); else attr_flg&=~(a);#define get_aflag(a) (attr_flg & (a))#define set_rflag(a,b) if (b) ctx->flags|=(a); else ctx->flags&=~(a);#define get_rflag(a) (ctx->flags & (a))static unsigned long mft_size,idx_size,spc,blocksize,mft_start;typedef struct { int flags; unsigned long target_vcn,curr_vcn,next_vcn,curr_lcn; unsigned long vcn_offset; char *mft,*cur_run;} read_ctx;#define NAME_BUF ((char *)(FSYS_BUF)) /* 4096 bytes */#define mmft ((char *)((FSYS_BUF)+4096))#define cmft (mmft+1024+1024+4096)#define sbuf (cmft+1024+1024+4096)#define cbuf (sbuf+4096)#define attr_flg valueat(cur_mft,0,unsigned short)#define attr_cur valueat(cur_mft,2,unsigned short)#define attr_nxt valueat(cur_mft,4,unsigned short)#define attr_end valueat(cur_mft,6,unsigned short)#define save_pos valueat(cur_mft,8,unsigned long)#define emft_buf (cur_mft+1024)#define edat_buf (cur_mft+2048)#define ofs2ptr(a) (cur_mft+(a))#define ptr2ofs(a) ((unsigned short)((a)-cur_mft))//#ifdef NTFS_DEBUG//#define dbg_printf printf//#else//#define dbg_printf if (0) printf//#endif#ifndef STAGE1_5#define dbg_printf if (((unsigned long)debug) >= 0x7FFFFFFF) printf#else#define dbg_printf if (0) printf#endif /* STAGE1_5 */static int fixup(char* buf,int len,char* magic){ int ss; char *pu; unsigned us; if (valueat(buf,0,unsigned long)!=valueat(magic,0,unsigned long)) { dbg_printf("%s label not found\n",magic); return 0; } ss=valueat(buf,6,unsigned short)-1; if (ss*blocksize!=len*512) { dbg_printf("Size not match %d!=%d\n",ss*blocksize,len*512); return 0; } pu=buf+valueat(buf,4,unsigned short); us=valueat(pu,0,unsigned short); buf-=2; while (ss>0) { buf+=blocksize; pu+=2; if (valueat(buf,0,unsigned short)!=us) { dbg_printf("Fixup signature not match\n"); return 0; } valueat(buf,0,unsigned short)=valueat(pu,0,unsigned short); ss--; } return 1;}static int read_mft(char* cur_mft,unsigned long mftno);static int read_attr(char* cur_mft,char* dest,unsigned long ofs,unsigned long len,int cached);static int read_data(char* cur_mft,char* pa,char* dest,unsigned long ofs,unsigned long len,int cached);static void init_attr(char* cur_mft){ attr_flg=0; attr_nxt=ptr2ofs(cur_mft+valueat(cur_mft,0x14,unsigned short)); attr_end=0;}static char* find_attr(char* cur_mft,unsigned char attr){ char* pa; if (get_aflag(AF_ALST)) {back: while (attr_nxt<attr_end) { attr_cur=attr_nxt; pa=ofs2ptr(attr_cur); attr_nxt+=valueat(pa,4,unsigned short); if (((unsigned char)*pa==attr) || (attr==0)) { char *new_pos; if (cur_mft==mmft) { if ((! devread(valueat(pa,0x10,unsigned long),0,512,emft_buf)) || (! devread(valueat(pa,0x14,unsigned long),0,512,emft_buf+512))) { dbg_printf("Read Error\n"); return NULL; } if (! fixup(emft_buf,mft_size,"FILE")) { dbg_printf("Invalid MFT at 0x%X\n",valueat(pa,0x10,unsigned long)); return NULL; } } else { if (! read_mft(emft_buf,valueat(pa,0x10,unsigned long))) return NULL; } new_pos=&emft_buf[valueat(emft_buf,0x14,unsigned short)]; while ((unsigned char)*new_pos!=0xFF) { if (((unsigned char)*new_pos==(unsigned char)*pa) && (valueat(new_pos,0xE,unsigned short)==valueat(pa,0x18,unsigned short))) { return new_pos; } new_pos+=valueat(new_pos,4,unsigned long); } dbg_printf("Can\'t find 0x%X in attribute list\n",(unsigned char)*pa); return NULL; } } return NULL; } pa=ofs2ptr(attr_nxt); while ((unsigned char)*pa!=0xFF) { attr_cur=attr_nxt; attr_nxt+=valueat(pa,4,unsigned long); if ((unsigned char)*pa==AT_ATTRIBUTE_LIST) attr_end=attr_cur; if (((unsigned char)*pa==attr) || (attr==0)) return pa; pa=ofs2ptr(attr_nxt); } if (attr_end) { pa=ofs2ptr(attr_end); if (pa[8]) { int n; n = (valueat(pa,0x30,unsigned long) + 511) & (~511); if (n>4096) { dbg_printf("Non-resident attribute list too large\n"); return NULL; } attr_cur=attr_end; if (! read_data(cur_mft,pa,edat_buf,0,n,0)) { dbg_printf("Fail to read non-resident attribute list\n"); return NULL; } attr_nxt=ptr2ofs(edat_buf); attr_end=ptr2ofs(edat_buf+valueat(pa,0x30,unsigned long)); } else { attr_nxt=attr_end+valueat(pa,0x14,unsigned short); attr_end=attr_end+valueat(pa,4,unsigned long); } set_aflag(AF_ALST,1); while (attr_nxt<attr_end) { pa=ofs2ptr(attr_nxt); if (((unsigned char)*pa==attr) || (attr==0)) break; attr_nxt+=valueat(pa,4,unsigned long); } if (attr_nxt>=attr_end) return NULL; if ((cur_mft==mmft) && (attr==AT_DATA)) { unsigned short new_pos; set_aflag(AF_GPOS,1); attr_cur=attr_nxt; pa=ofs2ptr(attr_cur); valueat(pa,0x10,unsigned long)=mft_start; valueat(pa,0x14,unsigned long)=mft_start+1; new_pos=attr_nxt+valueat(pa,4,unsigned short); while (new_pos<attr_end) { pa=ofs2ptr(new_pos); if ((unsigned char)*pa!=attr) break; if (! read_attr(cur_mft,pa+0x10,valueat(pa,0x10,unsigned long)*(mft_size << BLK_SHR),mft_size << BLK_SHR,0)) return NULL; new_pos+=valueat(pa,4,unsigned short); } attr_nxt=attr_cur; set_aflag(AF_GPOS,0); } goto back; } return NULL;}static char* locate_attr(char* cur_mft,unsigned char attr){ char* pa; init_attr(cur_mft); if ((pa=find_attr(cur_mft,attr))==NULL) return NULL; if (! get_aflag(AF_ALST)) { while (1) { if ((pa=find_attr(cur_mft,attr))==NULL) break; if (get_aflag(AF_ALST)) return pa; } init_attr(cur_mft); pa=find_attr(cur_mft,attr); } return pa;}static char* read_run_data(char* run,int nn,unsigned long* val,int sig){ unsigned long r, v; r = 0; v = 1; while (nn--) { r += v * (*(unsigned char *)(run++)); v <<= 8; } if ((sig) && (r & (v>>1))) r -=v; *val=r; return run;}static char* read_run_list(read_ctx* ctx,char* run){ int c1,c2; unsigned long val;back: c1=((unsigned char)(*run) & 0xF); c2=((unsigned char)(*run) >> 4); if (! c1) { char *cur_mft; cur_mft=ctx->mft; if ((cur_mft) && (get_aflag(AF_ALST))) { void (*save_hook)(unsigned long, unsigned long, unsigned long); save_hook=disk_read_func; disk_read_func=NULL; run=find_attr(cur_mft,(unsigned char)*ofs2ptr(attr_cur)); disk_read_func=save_hook; if (run) { if (run[8]==0) { dbg_printf("$DATA should be non-resident\n"); return NULL; } run+=valueat(run,0x20,unsigned short); ctx->curr_lcn=0; goto back; } } dbg_printf("Run list overflow\n"); return NULL; } run=read_run_data(run+1,c1,&val,0); // length of current VCN ctx->curr_vcn=ctx->next_vcn; ctx->next_vcn+=val; run=read_run_data(run,c2,&val,1); // offset to previous LCN ctx->curr_lcn+=val; set_rflag(RF_BLNK,(val==0)); return run;}static unsigned long comp_table[16][2];static int comp_head,comp_tail,cbuf_ofs,cbuf_vcn;static int decomp_nextvcn(void){ if (comp_head>=comp_tail) { dbg_printf("C1\n"); return 0; } if (! devread((comp_table[comp_head][1]-(comp_table[comp_head][0]-cbuf_vcn))*spc,0,spc << BLK_SHR,cbuf)) { dbg_printf("Read Error\n"); return 0; } cbuf_vcn++; if ((cbuf_vcn>=comp_table[comp_head][0])) comp_head++; cbuf_ofs=0; return 1;}static int decomp_getch(void){ if (cbuf_ofs>=(spc << BLK_SHR)) { if (! decomp_nextvcn()) return 0; } return (unsigned char)cbuf[cbuf_ofs++];}// Decompress a block (4096 bytes)static int decomp_block(char* dest){ unsigned short flg,cnt; flg=decomp_getch(); flg+=decomp_getch()*256; cnt=(flg & 0xFFF)+1; if (dest) { if (flg & 0x8000) { unsigned long bits,copied,tag; bits=copied=tag=0; while (cnt > 0) { if (copied > 4096) { dbg_printf("B1\n"); return 0; } if (! bits) { tag = decomp_getch(); bits = 8; cnt--; if (cnt<=0) break; } if (tag & 1) { unsigned long i, len, delta, code, lmask, dshift; code=decomp_getch(); code+=decomp_getch()*256; cnt-=2; if (! copied) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?