📄 inode.c
字号:
lowseconds |= result << 16; numerator2 = ((numerator2-result*D)<<8) | ((L>>8)&0xff); result = (numerator2 / D); /* shifted 8 right!! */ lowseconds |= result << 8; numerator2 = ((numerator2-result*D)<<8) | (L&0xff); result = (numerator2 / D); /* not shifted */ lowseconds |= result; return lowseconds;}ntfs_time64_t ntfs_unixutc2ntutc (ntfs_time_t t){ return ((t + (ntfs_time64_t)(369*365+89)*24*3600) * 10000000);}static int allocate_store(ntfs_volume *vol,ntfs_disk_inode *store,int count){ int i; if(store->count>count) return 0; if(store->size<count){ ntfs_mft_record* n=ntfs_malloc((count+4)*sizeof(ntfs_mft_record)); if(!n) return ENOMEM; if(store->size){ for(i=0;i<store->size;i++) n[i]=store->records[i]; ntfs_free(store->records); } store->size=count+4; store->records=n; } for(i=store->count;i<count;i++){ store->records[i].record=ntfs_malloc(vol->mft_recordsize); if(!store->records[i].record) return ENOMEM; store->count++; } return 0;}static void deallocate_store(ntfs_disk_inode* store){ int i; for(i=0;i<store->count;i++) ntfs_free(store->records[i].record); ntfs_free(store->records); store->count=store->size=0; store->records=0;}int layout_runs(ntfs_attribute *attr,char* rec,int* offs,int size){ int i,cluster,rclus,len,offset,coffs; ntfs_runlist *rl=attr->d.r.runlist; cluster=0; offset=*offs; for(i=0;i<attr->d.r.len;i++){ rclus=rl[i].cluster-cluster; len=rl[i].len; rec[offset]=0; if(offset+8>size) return E2BIG; /* it might still fit, but this simplifies testing */ if(len<0x100){ *(rec+offset)|=1; NTFS_PUTU8(rec+offset+1,len); coffs=2; }else if(len<0x10000){ *(rec+offset)|=2; NTFS_PUTU16(rec+offset+1,len); coffs=3; }else if(len<0x1000000){ *(rec+offset)|=3; NTFS_PUTU24(rec+offset+1,len); coffs=4; }else{ *(rec+offset)|=4; NTFS_PUTU32(rec+offset+1,len); coffs=5; } if(rl[i].cluster==0) /*compressed run*/ /*nothing*/; else if(rclus>-0x80 && rclus<0x7F){ *(rec+offset)|=0x10; NTFS_PUTS8(rec+offset+coffs,rclus); coffs+=1; }else if(rclus>-0x8000 && rclus<0x7FFF){ *(rec+offset)|=0x20; NTFS_PUTS16(rec+offset+coffs,rclus); coffs+=2; }else if(rclus>-0x800000 && rclus<0x7FFFFF){ *(rec+offset)|=0x30; NTFS_PUTS24(rec+offset+coffs,rclus); coffs+=3; }else{ *(rec+offset)|=0x40; NTFS_PUTS32(rec+offset+coffs,rclus); coffs+=4; } offset+=coffs; if(rl[i].cluster) cluster=rl[i].cluster; } *offs=offset; return 0;}static void count_runs(ntfs_attribute *attr,char *buf){ int first,count,last,i; first=0; for(i=0,count=0;i<attr->d.r.len;i++) count+=attr->d.r.runlist[i].len; last=first+count-1; NTFS_PUTU32(buf+0x10,first); NTFS_PUTU32(buf+0x18,last);} /* Try to layout ino into store. Return 0 on success, E2BIG if it does not fit, ENOMEM if memory allocation problem, EOPNOTSUP if beyound our capabilities */int layout_inode(ntfs_inode *ino,ntfs_disk_inode *store){ int offset,next,i; ntfs_attribute *attr; unsigned char *rec; int size,asize,aoffset; int error; if(ino->record_count>1) { ntfs_error("layout_inode: attribute lists not supported\n"); return EOPNOTSUPP; } error=allocate_store(ino->vol,store,1); if(error) return error; rec=store->records[0].record; size=ino->vol->mft_recordsize; store->records[0].recno=ino->records[0]; /* copy header */ offset=NTFS_GETU16(ino->attr+0x14); ntfs_memcpy(rec,ino->attr,offset); for(i=0;i<ino->attr_count;i++){ attr=ino->attrs+i; /* copy attribute header */ ntfs_memcpy(rec+offset,attr->header, min(sizeof(attr->header),size-offset)); /* consider overrun */ if(attr->namelen) /* named attributes are added later */ return EOPNOTSUPP; /* FIXME: assign attribute ID??? */ if(RESIDENT(&attr->header)){ asize=DATASIZE(&attr->header); aoffset=NTFS_GETU16(rec+offset+0x14); if(offset+aoffset+asize>size) return E2BIG; ntfs_memcpy(rec+offset+aoffset,attr->d.data,asize); next=offset+aoffset+asize; }else{ count_runs(attr,rec+offset); aoffset=NTFS_GETU16(rec+offset+0x20); next=offset+aoffset; error=layout_runs(attr,rec,&next,size); if(error) return error; } next=(next+7) & ~7; /* align to DWORD */ NTFS_PUTU16(rec+offset+4,next-offset); offset=next; } /* terminating attribute */ if(offset+8<size){ NTFS_PUTU32(rec+offset,0xFFFFFFFF); offset+=4; NTFS_PUTU32(rec+offset,0); offset+=4; }else return E2BIG; NTFS_PUTU32(rec+0x18,offset); return 0;} int update_inode(ntfs_inode *ino){ int error; ntfs_disk_inode store; ntfs_io io; int i,l; store.count=store.size=0; store.records=0; error=layout_inode(ino,&store); if(error==E2BIG){ /* should try: make attributes non-resident introduce extension records */ ntfs_error("cannot handle saving inode %x\n",ino->i_number); deallocate_store(&store); return EOPNOTSUPP; } if(error){ deallocate_store(&store); return error; } io.fn_get=ntfs_get; io.fn_put=0; for(i=0;i<store.count;i++){ ntfs_insert_fixups(store.records[i].record,ino->vol->blocksize); io.param=store.records[i].record; /* FIXME: is this the right way? */ l=ntfs_write_attr(ino->vol->mft_ino,AT_DATA,0, store.records[i].recno*ino->vol->mft_recordsize, &io,ino->vol->mft_recordsize); if(l!=ino->vol->mft_recordsize){ /* big trouble, partially written file */ ntfs_error("Please unmount: write error in inode %x\n",ino->i_number); deallocate_store(&store); /* FIXME: error code */ return EIO; } } return 0;}void ntfs_decompress(unsigned char* dest,unsigned char*src,ntfs_size_t l){ int head; int copied=0; unsigned char *stop; int bits; int tag=0; int clear_pos; while(1) { head = NTFS_GETU16(src) & 0xFFF; src += 2; stop = src+head; bits = 0; clear_pos=0; if(head==0xFFF) /* uncompressible */ { ntfs_memcpy(dest,src,0x1000); dest+=0x1000; copied+=0x1000; if(l==copied) return; continue; } while(src<=stop) { if(clear_pos>4096) { ntfs_error("Error 1 in decompress\n"); return; } if(!bits){ tag=NTFS_GETU8(src); bits=8; src++; if(src>stop) break; } if(tag & 1){ int i,len,delta,code,lmask,dshift; code = NTFS_GETU16(src); src+=2; if(!clear_pos) { ntfs_error("Error 2 in decompress\n"); return; } for(i=clear_pos-1,lmask=0xFFF,dshift=12;i>=0x10;i>>=1) { lmask >>= 1; dshift--; } delta = code >> dshift; len = (code & lmask) + 3; for(i=0; i<len; i++) { dest[clear_pos]=dest[clear_pos-delta-1]; clear_pos++; copied++; if(copied==l) return; } }else{ dest[clear_pos++]=NTFS_GETU8(src); src++; copied++; if(copied==l) return; } tag>>=1; bits--; } dest+=clear_pos; }}/* Caveat: No range checking in either ntfs_set_bit or ntfs_clear_bit */void ntfs_set_bit (unsigned char *byte, int bit){ byte += (bit >> 3); bit &= 7; *byte |= (1 << bit);}void ntfs_clear_bit (unsigned char *byte, int bit){ byte += (bit >> 3); bit &= 7; *byte &= ~(1 << bit);}/* We have to skip the 16 metafiles and the 8 reserved entries */int ntfs_new_inode (unsigned char *buffer, int length, int* result){ int byte; int bit; unsigned char value; for (byte = 3; byte < length; byte++) { value = buffer[byte]; for (bit = 0; bit < 8; bit++, value >>= 1) { if (!(value & 1)){ *result=byte*8+bit; return 0; } } } /* There is no free space. We must first extend the MFT. */ return EOPNOTSUPP;}static int add_mft_header (ntfs_inode *ino){ unsigned short fixup = 1; int fixup_count; int fixup_offset; int attr_offset; int record_size; unsigned char* mft; ntfs_volume *vol=ino->vol; fixup_offset = 0x2a; record_size = vol->mft_recordsize; fixup_count = record_size / vol->blocksize + 1; attr_offset = (0x2a + (2 * fixup_count) + 7) & ~7; mft=ino->attr; ntfs_bzero (mft, record_size); NTFS_PUTU32(mft + 0x00, 0x454c4946); /* file */ NTFS_PUTU16(mft + 0x04, 0x2a); /* offset to fixup */ NTFS_PUTU16(mft + 0x06, fixup_count); /* Number of fixups */ /* FIXME: sequence number. Regis recommended 5. */ NTFS_PUTU16(mft + 0x10, 5); NTFS_PUTU16(mft + 0x12, 1); /* hard link count */ NTFS_PUTU16(mft + 0x14, attr_offset); /* Offset to attributes */ NTFS_PUTU16(mft + 0x16, 1); /*FIXME: flags ?? */ NTFS_PUTU32(mft + 0x18, attr_offset + 0x08); /* In use */ NTFS_PUTU32(mft + 0x1c, record_size); /* Total size */ NTFS_PUTU16(mft + fixup_offset, fixup); /* Fixup word */ NTFS_PUTU32(mft + attr_offset, 0xffffffff); /* End marker */ return 0;}/* We need 0x48 bytes in total */static int add_standard_information (ntfs_inode *ino){ ntfs_time64_t now; char data[0x30]; char *position=data; int error; now = ntfs_now(); NTFS_PUTU64(position + 0x00, now); /* File creation */ NTFS_PUTU64(position + 0x08, now); /* Last modification */ NTFS_PUTU64(position + 0x10, now); /* Last mod for MFT */ NTFS_PUTU64(position + 0x18, now); /* Last access */ NTFS_PUTU64(position + 0x20, 0x00); /* MSDOS file perms */ NTFS_PUTU64(position + 0x28, 0); /* unknown */ error=ntfs_create_attr(ino,AT_STANDARD_INFORMATION,0,data,sizeof(data)); return error;}static int add_filename (ntfs_inode* ino, ntfs_inode* dir, const unsigned char *filename, int length){ unsigned char *position; unsigned int size; ntfs_time64_t now; int count; int error; unsigned char* data; ntfs_u64 ino_dir; /* work out the size */ size = 0x42 + 2 * length; data = ntfs_malloc(size); ntfs_bzero(data,size); /* search for a position */ position = data; ino_dir=dir->i_number; ino_dir|= ((ntfs_u64)(*(unsigned short*)(dir->attr+0x10)))<<48; NTFS_PUTU64(position, ino_dir); /* Inode num of dir */ now = ntfs_now(); NTFS_PUTU64(position + 0x08, now); /* File creation */ NTFS_PUTU64(position + 0x10, now); /* Last modification */ NTFS_PUTU64(position + 0x18, now); /* Last mod for MFT */ NTFS_PUTU64(position + 0x20, now); /* Last access */ /* Don't know */ NTFS_PUTU8(position+0x38, 0x20); /*archive*/ NTFS_PUTU8(position + 0x40, length); /* Filename length */ NTFS_PUTU8(position + 0x41, 0x01); /* File type (Win32) */ position += 0x42; for (count = 0; count < length; count++) { NTFS_PUTU16(position + 2 * count, filename[count]); } error=ntfs_create_attr(ino,AT_FILE_NAME,0,data,size); ntfs_free(data); return error;}int add_security (ntfs_inode* ino, ntfs_inode* dir){ int error; char *buf; int size; ntfs_attribute* attr; ntfs_io io; attr=ntfs_find_attr(dir,AT_SECURITY_DESCRIPTOR,0); if(!attr) return EOPNOTSUPP; /* need security in directory */ size = DATASIZE(&(attr->header)); if(size>512) return EOPNOTSUPP; buf=ntfs_malloc(size); if(!buf) return ENOMEM; io.fn_get=ntfs_get; io.fn_put=ntfs_put; io.param=buf; if(ntfs_read_attr(dir,AT_SECURITY_DESCRIPTOR,0,0,&io,size)!=size){ ntfs_free(buf); return EIO; /* FIXME */ } /* FIXME: consider ACL inheritance */ error=ntfs_create_attr(ino,AT_SECURITY_DESCRIPTOR,0,buf,size); ntfs_free(buf); return error;}static int add_data (ntfs_inode* ino, unsigned char *data, int length){ int error; error=ntfs_create_attr(ino,AT_DATA,0,data,length); return error;}/* We _could_ use 'dir' to help optimise inode allocation */int ntfs_alloc_inode (ntfs_inode*dir, ntfs_inode *result, char *filename, int namelen){ unsigned char buffer[512]; ntfs_io io; int size; int error; ntfs_volume* vol=dir->vol; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = buffer; size = ntfs_read_attr (vol->mft_ino, AT_BITMAP, 0, 0, &io, 512); if (size < 1) return (0); error=ntfs_new_inode (buffer, size, &(result->i_number)); if(error) { ntfs_error ("ntfs_get_empty_inode: no free inodes\n"); return error; } io.param = buffer; ntfs_set_bit (buffer, result->i_number); size = ntfs_write_attr (vol->mft_ino, AT_BITMAP, 0, 0, &io, size); if (size < 1) return ENOSPC; result->vol=vol; result->attr=ntfs_malloc(vol->mft_recordsize); result->attr_count=0; result->attrs=0; result->record_count=1; result->records=ntfs_malloc(8*sizeof(int)); result->records[0]=result->i_number; error=add_mft_header(result); if(error) return error; error=add_standard_information(result); if(error) return error; error=add_filename(result,dir,filename,namelen); if(error) return error; error=add_security(result,dir); /*FIXME: check error */ error=add_data(result,0,0); if(error) return error; return 0;}/* * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -