📄 super.c
字号:
/* * super.c * * Copyright (C) 1995-1997, 1999 Martin von L鰓is * Copyright (C) 1996-1997 R間is Duchesne * Copyright (C) 1999 Steve Dodd * Copyright (C) 2000 Anton Altparmakov */#include "ntfstypes.h"#include "struct.h"#include "super.h"#include <linux/errno.h>#include "macros.h"#include "inode.h"#include "support.h"#include "util.h"/* * All important structures in NTFS use 2 consistency checks : * . a magic structure identifier (FILE, INDX, RSTR, RCRD...) * . a fixup technique : the last word of each sector (called a fixup) of a * structure's record should end with the word at offset <n> of the first * sector, and if it is the case, must be replaced with the words following * <n>. The value of <n> and the number of fixups is taken from the fields * at the offsets 4 and 6. * * This function perform these 2 checks, and _fails_ if : * . the magic identifier is wrong * . the size is given and does not match the number of sectors * . a fixup is invalid */int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size){ int start, count, offset; ntfs_u16 fixup; if(!IS_MAGIC(record,magic)) return 0; start=NTFS_GETU16(record+4); count=NTFS_GETU16(record+6); count--; if(size && vol->blocksize*count != size) return 0; fixup = NTFS_GETU16(record+start); start+=2; offset=vol->blocksize-2; while(count--){ if(NTFS_GETU16(record+offset)!=fixup) return 0; NTFS_PUTU16(record+offset, NTFS_GETU16(record+start)); start+=2; offset+=vol->blocksize; } return 1;}/* Get vital informations about the ntfs partition from the boot sector */int ntfs_init_volume(ntfs_volume *vol,char *boot){ /* Historical default values, in case we don't load $AttrDef */ vol->at_standard_information=0x10; vol->at_attribute_list=0x20; vol->at_file_name=0x30; vol->at_volume_version=0x40; vol->at_security_descriptor=0x50; vol->at_volume_name=0x60; vol->at_volume_information=0x70; vol->at_data=0x80; vol->at_index_root=0x90; vol->at_index_allocation=0xA0; vol->at_bitmap=0xB0; vol->at_symlink=0xC0; /* Sector size */ vol->blocksize=NTFS_GETU16(boot+0xB); vol->clusterfactor=NTFS_GETU8(boot+0xD); vol->mft_clusters_per_record=NTFS_GETS8(boot+0x40); vol->index_clusters_per_record=NTFS_GETS8(boot+0x44); /* Just some consistency checks */ if(NTFS_GETU32(boot+0x40)>256) ntfs_error("Unexpected data #1 in boot block\n"); if(NTFS_GETU32(boot+0x44)>256) ntfs_error("Unexpected data #2 in boot block\n"); if(vol->index_clusters_per_record<0){ ntfs_error("Unexpected data #3 in boot block\n"); /* If this really means a fraction, setting it to 1 should be safe. */ vol->index_clusters_per_record=1; } /* in some cases, 0xF6 meant 1024 bytes. Other strange values have not been observed */ if(vol->mft_clusters_per_record<0 && vol->mft_clusters_per_record!=-10) ntfs_error("Unexpected data #4 in boot block\n"); vol->clustersize=vol->blocksize*vol->clusterfactor; if(vol->mft_clusters_per_record>0) vol->mft_recordsize= vol->clustersize*vol->mft_clusters_per_record; else vol->mft_recordsize=1<<(-vol->mft_clusters_per_record); vol->index_recordsize=vol->clustersize*vol->index_clusters_per_record; /* FIXME: long long value */ vol->mft_cluster=NTFS_GETU64(boot+0x30); /* This will be initialized later */ vol->upcase=0; vol->upcase_length=0; vol->mft_ino=0; return 0;}static void ntfs_init_upcase(ntfs_inode *upcase){ ntfs_io io;#define UPCASE_LENGTH 256 upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH); if( !upcase->vol->upcase ) return; io.fn_put=ntfs_put; io.fn_get=0; io.param=(char*)upcase->vol->upcase; io.size=2*UPCASE_LENGTH; ntfs_read_attr(upcase,upcase->vol->at_data,0,0,&io); upcase->vol->upcase_length = io.size / 2;}static intprocess_attrdef(ntfs_inode* attrdef,ntfs_u8* def){ int type = NTFS_GETU32(def+0x80); int check_type = 0; ntfs_volume *vol=attrdef->vol; ntfs_u16* name = (ntfs_u16*)def; if(ntfs_ua_strncmp(name,"$STANDARD_INFORMATION",64)==0){ vol->at_standard_information=type; check_type=0x10; }else if(ntfs_ua_strncmp(name,"$ATTRIBUTE_LIST",64)==0){ vol->at_attribute_list=type; check_type=0x20; }else if(ntfs_ua_strncmp(name,"$FILE_NAME",64)==0){ vol->at_file_name=type; check_type=0x30; }else if(ntfs_ua_strncmp(name,"$VOLUME_VERSION",64)==0){ vol->at_volume_version=type; check_type=0x40; }else if(ntfs_ua_strncmp(name,"$SECURITY_DESCRIPTOR",64)==0){ vol->at_security_descriptor=type; check_type=0x50; }else if(ntfs_ua_strncmp(name,"$VOLUME_NAME",64)==0){ vol->at_volume_name=type; check_type=0x60; }else if(ntfs_ua_strncmp(name,"$VOLUME_INFORMATION",64)==0){ vol->at_volume_information=type; check_type=0x70; }else if(ntfs_ua_strncmp(name,"$DATA",64)==0){ vol->at_data=type; check_type=0x80; }else if(ntfs_ua_strncmp(name,"$INDEX_ROOT",64)==0){ vol->at_index_root=type; check_type=0x90; }else if(ntfs_ua_strncmp(name,"$INDEX_ALLOCATION",64)==0){ vol->at_index_allocation=type; check_type=0xA0; }else if(ntfs_ua_strncmp(name,"$BITMAP",64)==0){ vol->at_bitmap=type; check_type=0xB0; }else if(ntfs_ua_strncmp(name,"$SYMBOLIC_LINK",64)==0 || ntfs_ua_strncmp(name,"$REPARSE_POINT",64)==0){ vol->at_symlink=type; check_type=0xC0; } if(check_type && check_type!=type){ ntfs_error("Unexpected type %x for %x\n",type,check_type); return EINVAL; } return 0;}intntfs_init_attrdef(ntfs_inode* attrdef){ ntfs_u8 *buf; ntfs_io io; int offset,error,i; ntfs_attribute *data; buf=ntfs_malloc(4050); /* 90*45 */ if(!buf)return ENOMEM; io.fn_put=ntfs_put; io.fn_get=ntfs_get; io.do_read=1; offset=0; data=ntfs_find_attr(attrdef,attrdef->vol->at_data,0); if(!data){ ntfs_free(buf); return EINVAL; } do{ io.param=buf; io.size=4050; error=ntfs_readwrite_attr(attrdef,data,offset,&io); for(i=0;!error && i<io.size-0xA0;i+=0xA0) error=process_attrdef(attrdef,buf+i); offset+=4096; }while(!error && io.size); ntfs_free(buf); return error;}/* ntfs_get_version will determine the NTFS version of the volume and will return the version in a BCD format, with the MSB being the major version number and the LSB the minor one. Otherwise return <0 on error. Example: version 3.1 will be returned as 0x0301. This has the obvious limitation of not coping with version numbers above 0x80 but that shouldn't be a problem... */int ntfs_get_version(ntfs_inode* volume){ ntfs_attribute *volinfo; volinfo = ntfs_find_attr(volume, volume->vol->at_volume_information, 0); if (!volinfo) return -EINVAL; if (!volinfo->resident) { ntfs_error("Volume information attribute is not resident!\n"); return -EINVAL; } return ((ntfs_u8*)volinfo->d.data)[8] << 8 | ((ntfs_u8*)volinfo->d.data)[9];}int ntfs_load_special_files(ntfs_volume *vol){ int error; ntfs_inode upcase, attrdef, volume; vol->mft_ino=(ntfs_inode*)ntfs_calloc(3*sizeof(ntfs_inode)); error=ENOMEM; ntfs_debug(DEBUG_BSD,"Going to load MFT\n"); if(!vol->mft_ino || (error=ntfs_init_inode(vol->mft_ino,vol,FILE_MFT))) { ntfs_error("Problem loading MFT\n"); return error; } ntfs_debug(DEBUG_BSD,"Going to load MIRR\n"); vol->mftmirr=vol->mft_ino+1; if((error=ntfs_init_inode(vol->mftmirr,vol,FILE_MFTMIRR))){ ntfs_error("Problem %d loading MFTMirr\n",error); return error; } ntfs_debug(DEBUG_BSD,"Going to load BITMAP\n"); vol->bitmap=vol->mft_ino+2; if((error=ntfs_init_inode(vol->bitmap,vol,FILE_BITMAP))){ ntfs_error("Problem loading Bitmap\n"); return error; } ntfs_debug(DEBUG_BSD,"Going to load UPCASE\n"); error=ntfs_init_inode(&upcase,vol,FILE_UPCASE); if(error)return error; ntfs_init_upcase(&upcase); ntfs_clear_inode(&upcase); ntfs_debug(DEBUG_BSD,"Going to load ATTRDEF\n"); error=ntfs_init_inode(&attrdef,vol,FILE_ATTRDEF); if(error)return error; error=ntfs_init_attrdef(&attrdef); ntfs_clear_inode(&attrdef); if(error)return error; /* Check for NTFS version and if Win2k version (ie. 3.0+) do not allow write access since the driver write support is broken, especially for Win2k. */ ntfs_debug(DEBUG_BSD,"Going to load VOLUME\n"); error = ntfs_init_inode(&volume,vol,FILE_VOLUME); if (error) return error; if ((error = ntfs_get_version(&volume)) >= 0x0300) { NTFS_SB(vol)->s_flags |= MS_RDONLY; ntfs_error("Warning! NTFS volume version is Win2k+: Mounting read-only\n"); } ntfs_clear_inode(&volume); if (error < 0) return error; ntfs_debug(DEBUG_BSD, "NTFS volume is version %d.%d\n", error >> 8, error & 0xff); return 0;}int ntfs_release_volume(ntfs_volume *vol){ if(vol->mft_ino){ ntfs_clear_inode(vol->mft_ino); ntfs_clear_inode(vol->mftmirr); ntfs_clear_inode(vol->bitmap); ntfs_free(vol->mft_ino); vol->mft_ino=0; } ntfs_free(vol->mft); ntfs_free(vol->upcase); return 0;}/* * Writes the volume size into vol_size. Returns 0 if successful * or error. */int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size ){ ntfs_io io; char *cluster0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -