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 + -
显示快捷键?