📄 attr.c
字号:
/* * attr.c * * Copyright (C) 1996 Martin von L鰓is * Copyright (C) 1996 Regis Duchesne */#include <errno.h>#include "ntfs.h"/* Look if an attribute already exists in the inode, and if not, create it */static int new_attr(ntfs_inode *ino,int type,void *name,int namelen, int *pos, int *found){ int do_insert=0; int i; for(i=0;i<ino->attr_count;i++) { int n=min(namelen,ino->attrs[i].namelen); int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n); /* * We assume that each attribute can be uniquely * identified by inode * number, attribute type and attribute name. */ if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){ *found=1; *pos=i; return 0; } /* attributes are ordered by type, then by name */ if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){ do_insert=1; break; } } /* re-allocate space */ if(ino->attr_count % 8 ==0) { ntfs_attribute* old=ino->attrs; ino->attrs = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)* sizeof(ntfs_attribute)); if(old){ ntfs_memcpy(ino->attrs,old,ino->attr_count*sizeof(ntfs_attribute)); ntfs_free(old); } } if(do_insert) ntfs_memcpy(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)* sizeof(ntfs_attribute)); ino->attr_count++; ino->attrs[i].type=type; ino->attrs[i].namelen=namelen; ino->attrs[i].name=name; *pos=i; *found=0; return 0;}int ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr){ int size=DATASIZE(&attr->header); if(size>0){ /* FIXME: read data, free clusters */ return EOPNOTSUPP; } NTFS_PUTU8(((char*)&attr->header)+8,0); NTFS_PUTU16(((char*)&attr->header)+0x10,size); return 0;}/* Resize the attribute to a newsize */int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute* attr,int newsize){ int error=0; int oldsize=DATASIZE(&attr->header); int clustersize=ino->vol->clustersize; int i,count,newlen,newcount; ntfs_runlist *rl; if(newsize==oldsize) return 0; /* modifying compressed attributes not supported yet */ if(COMPRESSED(&attr->header)) return EOPNOTSUPP; /* modifying large files not supported yet */ if(ino->record_count>1) return EOPNOTSUPP; if(RESIDENT(&attr->header)){ void *v; /* making resident attributes non-resident not supported yet */ /* FIXME: check is not sufficient */ if(newsize>ino->vol->mft_recordsize) return EOPNOTSUPP; v=attr->d.data; if(newsize){ attr->d.data=ntfs_malloc(newsize); if(!attr->d.data) return ENOMEM; ntfs_bzero(attr->d.data+oldsize,newsize); ntfs_memcpy(attr->d.data,v,min(newsize,oldsize)); }else attr->d.data=0; ntfs_free(v); NTFS_PUTU16((&attr->header)+0x10,newsize); return 0; } /* non-resident attribute */ rl=attr->d.r.runlist; if(newsize<oldsize){ for(i=0,count=0;i<attr->d.r.len;i++){ if((count+rl[i].len)*clustersize>newsize) break; count+=rl[i].len; } newlen=i+1; /* free unused clusters in current run, unless sparse */ newcount=count; if(rl[i].cluster!=-1){ int rounded=newsize-count*clustersize; rounded=(rounded+clustersize-1)/clustersize; error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster+rounded, rl[i].len-rounded); if(error) return error; /* FIXME: incomplete operation */ rl[i].len=rounded; newcount=count+rounded; } /* free all other runs */ for(i++;i<attr->d.r.len;i++) if(rl[i].cluster!=-1){ error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,rl[i].len); if(error) return error; /* FIXME: incomplete operation */ } /* FIXME? free space for extra runs in memory */ attr->d.r.len=newlen; }else{ /* extend attribute */ return EOPNOTSUPP; } /* fill in new sizes */ NTFS_PUTU64(((char*)&(attr->header))+0x28,newcount*clustersize); /* allocated disk space */ NTFS_PUTU64(((char*)&(attr->header))+0x30,newsize); /*size*/ NTFS_PUTU64(((char*)&(attr->header))+0x38,newsize); /*initialized*/ if(!newsize) error=ntfs_make_attr_resident(ino,attr); return error;}int ntfs_create_attr(ntfs_inode *ino,int anum,char* aname,void *data,int dsize){ void *name; int namelen; int found,i; int dstart; int error; ntfs_attribute *attr; char *h; if(dsize>ino->vol->mft_recordsize) /* FIXME: non-resident attributes */ return EOPNOTSUPP; if(aname){ namelen=ntfs_strlen(aname); name=ntfs_malloc(2*namelen); ntfs_ascii2uni(name,aname,namelen); }else{ name=0; namelen=0; } new_attr(ino,anum,name,namelen,&i,&found); if(found){ ntfs_free(name); return EEXIST; } attr=ino->attrs+i; ntfs_bzero(attr->header,sizeof(attr->header)); h=attr->header; NTFS_PUTU32(h,anum); /* type */ NTFS_PUTU8(h+8,0); /* resident */ NTFS_PUTU8(h+9,namelen); NTFS_PUTU8(h+0xA,0x18); /* start of name or resident data */ NTFS_PUTU8(h+0xC,0); /* not compressed */ /* allocate a new number. FIXME: Should this happen on inode writeback? FIXME: extensions records not supported */ error=ntfs_allocate_attr_number(ino,&i); if(error) return error; NTFS_PUTU16(h+0xE,i); NTFS_PUTU16(h+0x10,dsize); dstart=0x18+namelen*2; /* start data after name */ dstart=(dstart+7)/8*8; /* round to next multiple of 8 */ NTFS_PUTU16(h+0x14,dstart); attr->d.data=ntfs_malloc(dsize); ntfs_memcpy(attr->d.data,data,dsize); return 0;}/* Store in the inode readable information about a run */void ntfs_insert_run(ntfs_attribute *attr,int cnum,int cluster,int len){ /* (re-)allocate space if necessary */ if(attr->d.r.len % 8 == 0) { ntfs_runlist* old; old=attr->d.r.runlist; attr->d.r.runlist=ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist)); if(old) { ntfs_memcpy(attr->d.r.runlist,old,attr->d.r.len *sizeof(ntfs_runlist)); ntfs_free(old); } } if(attr->d.r.len>cnum) ntfs_memcpy(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum, (attr->d.r.len-cnum)*sizeof(ntfs_runlist)); attr->d.r.runlist[cnum].cluster=cluster; attr->d.r.runlist[cnum].len=len; attr->d.r.len++;}/* Non-resident attributes are stored in runs (intervals of clusters). * * This function stores in the inode readable information about a non-resident * attribute. */static int process_runs(ntfs_inode *ino,ntfs_attribute* attr, unsigned char *data){ int startvcn,endvcn; int vcn,cnum; int cluster,len,ctype; startvcn = NTFS_GETU64(data+0x10); endvcn = NTFS_GETU64(data+0x18); /* check whether this chunk really belongs to the end */ for(cnum=0,vcn=0;cnum<attr->d.r.len;cnum++) vcn+=attr->d.r.runlist[cnum].len; if(vcn!=startvcn) { ntfs_error("Problem with runlist in extended record\n"); return -1; } if(!endvcn) { endvcn = NTFS_GETU64(data+0x28)-1; /* allocated length */ endvcn /= ino->vol->clustersize; } data=data+NTFS_GETU16(data+0x20); cnum=attr->d.r.len; cluster=0; for(vcn=startvcn; vcn<=endvcn; vcn+=len) { if(decompress_run(&data,&len,&cluster,&ctype)) return -1; if(ctype) ntfs_insert_run(attr,cnum,-1,len); else ntfs_insert_run(attr,cnum,cluster,len); cnum++; } return 0;} /* Insert the attribute starting at attr in the inode ino */int ntfs_insert_attribute(ntfs_inode* ino,unsigned char* attr){ int i,found; int type; short int *name; int namelen; void *data; int datasize; type = NTFS_GETU32(attr); namelen = NTFS_GETU8(attr+9); /* read the attribute's name if it has one */ if(!namelen) name=0; else { /* 1 Unicode character fits in 2 bytes */ name=ntfs_malloc(2*namelen); ntfs_memcpy(name,attr+NTFS_GETU16(attr+10),2*namelen); } new_attr(ino,type,name,namelen,&i,&found); /* We can have in one inode two attributes with type 0x00000030 (File Name) and without name */ if(found && /*FIXME*/type!=AT_FILE_NAME) { process_runs(ino,ino->attrs+i,attr); return 0; } ntfs_memcpy(&ino->attrs[i].header,attr,sizeof(ino->attrs[i].header)); datasize=DATASIZE(attr); if(RESIDENT(attr)) { data=attr+NTFS_GETU16(attr+0x14); ino->attrs[i].d.data = (void*)ntfs_malloc(datasize); ntfs_memcpy(ino->attrs[i].d.data,data,datasize); }else{ ino->attrs[i].d.r.runlist=0; ino->attrs[i].d.r.len=0; process_runs(ino,ino->attrs+i,attr); } return 0;}/* * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -