📄 inode.c
字号:
/* * inode.c * * Copyright (C) 1995,1996 Martin von L鰓is * Copyright (C) 1996 Albert D. Cahalan * Copyright (C) 1996 Regis Duchesne */#include <errno.h>#include "ntfs.h"#include "config.h"int ntfs_init_inode(ntfs_inode *ino,ntfs_volume* vol,int inum){ ntfs_debug("Initializing inode %x\n",inum); ino->i_number=inum; ino->vol=vol; ino->attr=ntfs_malloc(vol->mft_recordsize); if(ntfs_read_mft_record(vol,inum,ino->attr)==-1){ ntfs_debug("init inode: %x failed\n",inum); return -1; } ntfs_debug("Init: got mft %x\n",inum); ino->attr_count=0; ino->record_count=0; ino->records=0; ino->attrs=0; ntfs_load_attributes(ino); ntfs_debug("Init: done %x\n",inum); return 0;}void ntfs_clear_inode(ntfs_inode *ino){ int i; ntfs_free(ino->attr); ntfs_free(ino->records); for(i=0;i<ino->attr_count;i++) { if(ino->attrs[i].name) ntfs_free(ino->attrs[i].name); if(RESIDENT(&ino->attrs[i].header)) { if(ino->attrs[i].d.data) ntfs_free(ino->attrs[i].d.data); }else{ if(ino->attrs[i].d.r.runlist) ntfs_free(ino->attrs[i].d.r.runlist); } } ntfs_free(ino->attrs);}/* Insert all attributes from the record mftno of the MFT in the inode ino */void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno){ int i; char *it; int type,len; /* check for duplicate */ for(i=0;i<ino->record_count;i++) if(ino->records[i]==mftno) return; /* (re-)allocate space if necessary */ if(ino->record_count % 8==0) { int *old=ino->records; ino->records=ntfs_malloc((ino->record_count+8)*sizeof(int)); if(old) { for(i=0;i<ino->record_count;i++) ino->records[i]=old[i]; ntfs_free(old); } } ino->records[ino->record_count]=mftno; ino->record_count++; it = mft + NTFS_GETU16(mft + 0x14); do{ type=NTFS_GETU32(it); len=NTFS_GETU32(it+4); if(type!=-1) ntfs_insert_attribute(ino,it); it+=len; }while(type!=-1); /* attribute list ends with type -1 */}/* Read and insert all the attributes of an 'attribute list' attribute */static int parse_attributes(ntfs_inode* ino,void *alist,int len){ char *mft; int mftno,l; int last_mft=-1; mft=ntfs_malloc(ino->vol->mft_recordsize); while(len>0) { /* process an attribute description */ mftno=NTFS_GETU32(alist+0x10); /* BUG: this is u64 */ if(mftno!=last_mft){ last_mft=mftno; /* FIXME: avoid loading record if it's already processed */ if(ntfs_read_mft_record(ino->vol,mftno,mft)==-1) return -1; ntfs_insert_mft_attributes(ino,mft,mftno); } l=NTFS_GETU16(alist+4); len-=l; alist+=l; } ntfs_free(mft); return 0;}void ntfs_load_attributes(ntfs_inode* ino){ ntfs_attribute *alist; int datasize; int offset,len; char *buf; ntfs_debug("load_attributes %x 1\n",ino->i_number); ntfs_insert_mft_attributes(ino,ino->attr,ino->i_number); ntfs_debug("load_attributes %x 2\n",ino->i_number); alist=ntfs_find_attr(ino,AT_ATTRIBUTE_LIST,0); ntfs_debug("load_attributes %x 3\n",ino->i_number); if(!alist) return; ntfs_debug("load_attributes %x 4\n",ino->i_number); datasize=DATASIZE(&alist->header); if(RESIDENT(&alist->header)) { parse_attributes(ino,alist->d.data,datasize); return; } buf=ntfs_malloc(1024); for(offset=0;datasize;datasize-=len) { ntfs_io io; io.fn_put=ntfs_put; io.fn_get=0; io.param=buf; len=min(datasize,1024); /* FIXME: this is really broken if there the attribute list is larger than 1024 bytes and 1024 bytes is not a attribute record border */ ntfs_read_attr(ino,AT_ATTRIBUTE_LIST,0,offset,&io,len); parse_attributes(ino,buf,len); } ntfs_debug("load_attributes %x 5\n",ino->i_number); ntfs_free(buf);} /* Check and fixup a MFT record */int ntfs_check_mft_record(ntfs_volume *vol,char *record){ return ntfs_fixup_record(vol, record, "FILE", vol->mft_recordsize);}/* Return (in result) the value indicating the next available attribute chunk number. Works for inodes w/o extension records only */int ntfs_allocate_attr_number(ntfs_inode *ino, int *result){ if(ino->record_count!=1) return EOPNOTSUPP; *result=NTFS_GETU16(ino->attr+0x28); NTFS_PUTU16(ino->attr+0x28, (*result)+1); return 0;}/* find the location of an attribute in the inode. A name of NULL indicates unnamed attributes. Return pointer to attribute or NULL if not found */char *ntfs_get_attr(ntfs_inode *ino,int attr,char *name){ /* location of first attribute */ char *it= ino->attr + NTFS_GETU16(ino->attr + 0x14); int type; int len; /* Only check for magic DWORD here, fixup should have happened before */ if(!IS_MFT_RECORD(ino->attr))return 0; do{ type=NTFS_GETU32(it); len=NTFS_GETU16(it+4); /* We found the attribute type. Is the name correct, too? */ if(type==attr) { int namelen=NTFS_GETU8(it+9); char *name_it; /* match given name and attribute name if present, make sure attribute name is Unicode */ for(name_it=it+NTFS_GETU16(it+10);namelen; name++,name_it+=2,namelen--) if(*name_it!=*name || name_it[1])break; if(!namelen)break; } it+=len; }while(type!=-1); /* attribute list end with type -1 */ if(type==-1)return 0; return it;}/* Search in an inode an attribute by type and name */ntfs_attribute* ntfs_find_attr(ntfs_inode *ino,int type,char *name){ int i; if(!ino){ ntfs_error("ntfs_find_attr: NO INODE!\n"); return 0; } for(i=0;i<ino->attr_count;i++) { if(type==ino->attrs[i].type) { if(!name && !ino->attrs[i].name) return ino->attrs+i; if(name && !ino->attrs[i].name) return 0; if(!name && ino->attrs[i].name) return 0; if(ntfs_ua_strncmp(ino->attrs[i].name,name,ntfs_strlen(name))==0) return ino->attrs+i; } if(type<ino->attrs[i].type) return 0; } return 0;}int ntfs_get_attr_size(ntfs_inode*ino,int type,char*name){ ntfs_attribute *attr=ntfs_find_attr(ino,type,name); if(!attr)return 0; return DATASIZE(&attr->header);} int ntfs_attr_is_resident(ntfs_inode*ino,int type,char*name){ ntfs_attribute *attr=ntfs_find_attr(ino,type,name); if(!attr)return 0; return RESIDENT(&attr->header);} /* * A run is coded as a type indicator, an unsigned length, and a signed cluster * offset. * . To save space, length and offset are fields of variable length. The low * nibble of the type indicates the width of the length :), the high nibble * the width of the offset. * . The first offset is relative to cluster 0, later offsets are relative to * the previous cluster. * * This function decodes a run. Length is an output parameter, data and cluster * are in/out parameters. */int decompress_run(unsigned char **data,int *length,int *cluster,int *ctype){ unsigned char type=*(*data)++; *ctype=0; switch(type & 0xF) { case 1: *length=NTFS_GETU8(*data);(*data)++;break; case 2: *length=NTFS_GETU16(*data); *data+=2; break; case 3: *length = NTFS_GETU24(*data); *data+=3; break; /* TODO: case 4-8 */ default: ntfs_error("Can't decode run type field %x\n",type); return -1; } switch(type & 0xF0) { case 0: *ctype=2;break; case 0x10: *cluster+=NTFS_GETS8(*data);(*data)++;break; case 0x20: *cluster+=NTFS_GETS16(*data); *data+=2; break; case 0x30: *cluster+=NTFS_GETS24(*data); *data+=3; break; /* TODO: case 0x40-0x80 */ default: ntfs_error("Can't decode run type field %x\n",type); return -1; } return 0;}/* Reads l bytes of the attribute (attr,name) of ino starting at offset on vol into buf. Returns the number of bytes read. 0 is end of attribute, -1 is error */int ntfs_readwrite_attr(ntfs_inode *ino,int type, char *name,int offset,ntfs_io *dest,int l){ ntfs_attribute *attr; int datasize,resident,rnum,compressed; int cluster,s_cluster,vcn,len,chunk,copied; int s_vcn,s_vcn_comp; int clustersize; attr=ntfs_find_attr(ino,type,name); if(!attr) return -1; clustersize=ino->vol->clustersize; datasize=DATASIZE(&attr->header); if(dest->do_read) { if(offset>datasize) return 0; if(offset+l>=datasize) l=datasize-offset; }else{ /* if writing beyond end, extend attribute */ } resident=RESIDENT(&attr->header); if(resident) { if(dest->do_read) dest->fn_put(dest,attr->d.data+offset,l); else { dest->fn_get(attr->d.data+offset,dest,l); update_inode(ino); } return l; } compressed=COMPRESSED(&attr->header); vcn=0; s_vcn = offset/clustersize; s_vcn_comp = compressed ? (s_vcn/16)*16 : s_vcn; for(rnum=0;vcn+attr->d.r.runlist[rnum].len<=s_vcn_comp;rnum++) vcn+=attr->d.r.runlist[rnum].len; copied=0; while(l) { s_vcn = offset/clustersize; s_vcn_comp = compressed ? (s_vcn/16)*16 : s_vcn; cluster=attr->d.r.runlist[rnum].cluster; len=attr->d.r.runlist[rnum].len; if(compressed && cluster==-1) { /* We are in the middle of a sparse data block */ char *sparse = ntfs_malloc(512); if(!sparse)return -1; ntfs_bzero(sparse,512); chunk = min((vcn+len)*clustersize-offset,l); while(chunk) { int i=min(chunk,512); dest->fn_put(dest,sparse,i); chunk-= i; } /* restore original value */ chunk = min((vcn+len)*clustersize-offset,l); ntfs_free(sparse); }else if(compressed) { char *comp,*comp1; char *decomp; int got,vcn_comp1; int offs1; /* FIXME: writing compressed files */ if(!dest->do_read) return -1; if(!(comp= ntfs_malloc(16*clustersize))) return -1; if(!(decomp = ntfs_malloc(16*clustersize))) { ntfs_free(comp); return -1; } comp1=comp; got=0; vcn_comp1=s_vcn_comp; do{ ntfs_io io; int l1=min(len*clustersize,16*clustersize-got); io.do_read=1; io.fn_put=ntfs_put; io.fn_get=0; io.param=comp1; if(!ntfs_getput_clusters(ino->vol,cluster+vcn_comp1-vcn,0, l1,&io)) { ntfs_free(comp);ntfs_free(decomp);return -1; } comp1+=len*clustersize; if(l1==len*clustersize){ rnum++; vcn+=len; cluster=attr->d.r.runlist[rnum].cluster; len=attr->d.r.runlist[rnum].len; vcn_comp1=vcn; } got+=l1; }while(cluster!=-1 && got<16*clustersize); /*until 'emtpy' run*/ offs1 = offset-s_vcn_comp*clustersize; if(cluster!=-1){ /* uncompressible */ comp1 = comp; }else{ ntfs_decompress(decomp,comp,min(offs1+l,16*clustersize)); comp1 = decomp; } chunk = min(16*clustersize-offs1,l); dest->fn_put(dest,comp1+offs1,chunk); ntfs_free(comp); ntfs_free(decomp); }else{ s_cluster = cluster+s_vcn-vcn; chunk=min((vcn+len)*clustersize-offset,l); if(!ntfs_getput_clusters(ino->vol,s_cluster, offset-s_vcn*clustersize,chunk,dest)) { ntfs_error("Read error\n"); return copied; } } l-=chunk; copied+=chunk; offset+=chunk; if(l && offset>=((vcn+len)*clustersize)) { rnum++; vcn+=len; cluster = attr->d.r.runlist[rnum].cluster; len = attr->d.r.runlist[rnum].len; } } return copied;}int ntfs_read_attr(ntfs_inode *ino,int attr, char *name,int offset,ntfs_io *buf,int l){ buf->do_read=1; return ntfs_readwrite_attr(ino,attr,name,offset,buf,l);}int ntfs_write_attr(ntfs_inode *ino,int attr, char *name,int offset,ntfs_io *buf,int l){ buf->do_read=0; return ntfs_readwrite_attr(ino,attr,name,offset,buf,l);}int ntfs_vcn_to_lcn(ntfs_inode *ino,int vcn){ int rnum; ntfs_attribute *data=ntfs_find_attr(ino,AT_DATA,0); /* It's hard to give an error code */ if(!data)return -1; if(RESIDENT(&data->header))return -1; if(COMPRESSED(&data->header))return -1; if(DATASIZE(&data->header)<vcn*ino->vol->clustersize)return -1; for(rnum=0;rnum<data->d.r.len && vcn>data->d.r.runlist[rnum].len;rnum++) vcn-=data->d.r.runlist[rnum].len; return data->d.r.runlist[rnum].cluster+vcn;}/* copy len unicode characters from from to to :) */void ntfs_uni2ascii(char *to,char *from,int len){ int i; for(i=0;i<len;i++) to[i]=from[2*i]; to[i]='\0';}/* copy len asci characters from from to to :) */void ntfs_ascii2uni(short int *to,char *from,int len){ int i; for(i=0;i<len;i++) to[i]=from[i]; to[i]=0;}/* strncmp for Unicode strings */int ntfs_uni_strncmp(short int* a,short int *b,int n){ int i; for(i=0;i<n;i++) { if(a[i]<b[i]) return -1; if(b[i]<a[i]) return 1; } return 0;}/* strncmp between Unicode and ASCII strings */int ntfs_ua_strncmp(short int* a,char* b,int n){ int i; for(i=0;i<n;i++) { if(a[i]<b[i]) return -1; if(b[i]<a[i]) return 1; } return 0;}/* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units) into Unix UTC (based 1.1.1970, in seconds) */ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc){/* * This is very gross because * 1: We must do 64-bit division on a 32-bit machine * 2: We can't use libgcc for long long operations in the kernel * 3: Floating point math in the kernel would corrupt user data */ const unsigned int D = 10000000; unsigned int H = (ntutc >> 32); unsigned int L = (unsigned int)ntutc; unsigned int numerator2; unsigned int lowseconds; unsigned int result; /* It is best to subtract 0x019db1ded53e8000 first. */ /* Then the 1601-based date becomes a 1970-based date. */ if(L < (unsigned)0xd53e8000) H--; L -= (unsigned)0xd53e8000; H -= (unsigned)0x019db1de; /* * Now divide 64-bit numbers on a 32-bit machine :-) * With the subtraction already done, the result fits in 32 bits. * The numerator fits in 56 bits and the denominator fits * in 24 bits, so we can shift by 8 bits to make this work. */ numerator2 = (H<<8) | (L>>24); result = (numerator2 / D); /* shifted 24 right!! */ lowseconds = result << 24; numerator2 = ((numerator2-result*D)<<8) | ((L>>16)&0xff); result = (numerator2 / D); /* shifted 16 right!! */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -