📄 ntfs_fs.c
字号:
MOD_DEC_USE_COUNT; return 0; } /* Read the superblock assuming 512 byte blocks for now */ set_blocksize(dev,512); /* Read the boot block to get the location of the MFT */ if(!(bh=bread(dev,0,512))) { printk("Reading super block failed\n"); sb->s_dev=0; ntfs_free(vol); unlock_super(sb); MOD_DEC_USE_COUNT; return NULL; } NTFS_DEBUG("Done reading boot block\n"); /* Check for 'NTFS' magic at offset 3 */ if(!IS_NTFS_VOLUME(bh->b_data)){ NTFS_DEBUG("Not a NTFS volume\n"); ntfs_free(vol); sb->s_dev=0; brelse(bh); unlock_super(sb); MOD_DEC_USE_COUNT; return NULL; } NTFS_DEBUG("Going to init volume\n"); ntfs_init_volume(vol,bh->b_data); NTFS_SB(vol)=sb; NTFS_SB2VOL(sb)=vol; NTFS_DEBUG("Done to init volume\n"); sb->s_blocksize=vol->clustersize; for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i;i>>=1) sb->s_blocksize_bits++; /* inform the kernel that a device block is a NTFS cluster */ set_blocksize(dev,sb->s_blocksize); NTFS_DEBUG("set_blocksize\n"); NTFS_DEBUG("MFT record at cluster 0x%X\n",vol->mft_cluster); brelse(bh); /* Allocate a MFT record */ /* Handle cases where mft record is smaller than a cluster */ vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize)); /* read the MFT record 0 */ /* If there is more than one MFT record per cluster, read just one cluster */ for(i=0;i<max(vol->mft_clusters_per_record,1);i++){ if(!(bh=bread(dev,vol->mft_cluster+i,vol->clustersize))) { NTFS_DEBUG("Could not read MFT record 0\n"); sb->s_dev=0; unlock_super(sb); MOD_DEC_USE_COUNT; return NULL; } ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize); brelse(bh); NTFS_DEBUG("Read cluster %x\n",vol->mft_cluster+i); } /* Check and fixup MFT record 0 */ if(!ntfs_check_mft_record(vol,vol->mft)){ NTFS_DEBUG("Invalid MFT record 0\n"); sb->s_dev=0; unlock_super(sb); MOD_DEC_USE_COUNT; return NULL; } /* inform the kernel about which super operations are available */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; NTFS_DEBUG("Reading master and upcase files\n"); ntfs_load_special_files(vol); unlock_super(sb); NTFS_DEBUG("Getting RootDir\n"); /* get the root directory */ if(!(sb->s_mounted=iget(sb,FILE_ROOT))){ sb->s_dev=0; NTFS_DEBUG("Could not get root dir inode\n"); MOD_DEC_USE_COUNT; return NULL; } NTFS_DEBUG("read_super: done\n"); return sb;}static void ntfs_put_super(struct super_block *sb){ ntfs_volume *vol=NTFS_SB2VOL(sb); NTFS_DEBUG("ntfs_put_super\n"); lock_super(sb); if(vol->mft_ino){ ntfs_clear_inode(vol->mft_ino); ntfs_free(vol->mft_ino); vol->mft_ino=0; } sb->s_dev=0; ntfs_free(vol->mft); ntfs_free(vol->upcase); ntfs_free(sb->u.generic_sbp); sb->u.generic_sbp=0; unlock_super(sb); MOD_DEC_USE_COUNT;}static int ntfs_remount_fs(struct super_block *sb, int* flags, char* options){ if(parse_options(sb,(ntfs_volume*)sb->u.generic_sbp, options)) { if((*flags & MS_RDONLY) && (sb->s_flags && MS_RDONLY)) return 0; if(*flags & MS_RDONLY) /* changing from rw to ro */ sb->s_flags |= MS_RDONLY; else if(sb->s_flags & MS_RDONLY) /* changing from rw to rw */ sb->s_flags &= ~MS_RDONLY; return 0; } else return -EINVAL;}static int ntfs_lookup(struct inode *dir, const char *name, int len, struct inode **result){ struct inode *res=0; unsigned long ino; char *item=0; ntfs_iterate_s walk; int error; NTFS_DEBUG("Looking up %s in %x\n",name,(unsigned)dir->i_ino); if(strncmp(name,".",len)==0){ *result=dir; return 0; } if(dcache_lookup(dir,name,len,&ino)) { if(!(*result = iget(dir->i_sb,ino))) { iput(dir); return -EACCES; } iput(dir); return 0; } if(strncmp(name,"..",len)==0) { /*NTFS_DEBUG(".. not supported\n");*/ /* What if a directory has more than one name? */ /* FIXME: support for segments */ ntfs_attribute *attr=ntfs_find_attr((ntfs_inode*)dir->u.generic_ip, AT_FILE_NAME,NULL); if(!attr){ NTFS_DEBUG(".. not found\n"); iput(dir); return -ENOENT; } if(!(*result = iget(dir->i_sb,NTFS_GETU32(attr->d.data)))) { iput(dir); return -EACCES; } iput(dir); return 0; } /* convert to wide string */ error=ntfs_decodeuni(NTFS_INO2VOL(dir),name,len, &walk.name,&walk.namelen); if(error) return error; item=ntfs_malloc(ITEM_SIZE); /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ walk.type=BY_NAME; walk.dir=(ntfs_inode*)dir->u.generic_ip; walk.result=item; if(ntfs_getdir_byname(&walk)) { res=iget(dir->i_sb,NTFS_GETU32(item)); dcache_add(dir, name, len, NTFS_GETU32(item)); } iput(dir); *result=res; ntfs_free(item); ntfs_free(walk.name); return res?0:-ENOENT;}static int ntfs_bmap(struct inode *ino,int block){ int ret=ntfs_vcn_to_lcn((ntfs_inode*)ino->u.generic_ip,block); NTFS_DEBUG("bmap of %lx,block %x is %x\n", ino->i_ino,block,ret); return (ret==-1) ? 0:ret;}struct file_operations ntfs_file_operations = { NULL, /* lseek */ ntfs_read, ntfs_write, NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ generic_file_mmap, NULL, /* open */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL /* revalidate */};struct inode_operations ntfs_inode_operations = { &ntfs_file_operations, NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ ntfs_bmap, NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */};struct file_operations ntfs_file_operations_nommap = { NULL, /* lseek */ ntfs_read, ntfs_write, NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL /* revalidate */};struct inode_operations ntfs_inode_operations_nobmap = { &ntfs_file_operations_nommap, NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */};struct file_operations ntfs_dir_operations = { NULL, /* lseek */ NULL, /* read */ NULL, /* write */ ntfs_readdir, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL /* revalidate */};struct inode_operations ntfs_dir_inode_operations = { &ntfs_dir_operations, NULL, /* create */ ntfs_lookup, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */};struct super_operations ntfs_super_operations = { ntfs_read_inode, NULL, /* notify_change */ NULL, /* write_inode */ ntfs_put_inode, ntfs_put_super, NULL, /* write_super */ ntfs_statfs, ntfs_remount_fs, /* remount */};/* This structure defines the filesystem * * Define SECOND if you cannot unload ntfs, and want to avoid rebooting * for just one more test */struct file_system_type ntfs_fs_type = { ntfs_read_super,/* Entry point of the filesystem */#ifndef SECOND "ntfs", /* Name of the filesystem, as used in mount -t ntfs */#else "ntfs2",#endif 1, /* The filesystem requires a block device to be mounted on */ NULL /* Will point to the next filesystem in the kernel table */};int init_ntfs_fs(void){ /* Uncomment this if you don't trust klogd. There are reasons not to trust it. */#if 0 extern int console_loglevel; console_loglevel=15;#endif NTFS_DEBUG("registering %s\n",ntfs_fs_type.name); printk(KERN_NOTICE "NTFS version " NTFS_VERSION "\n"); /* add this filesystem to the kernel table of filesystems */ return register_filesystem(&ntfs_fs_type);}#ifdef MODULE/* Every module must contain 2 particular functions whose names are predefined : * . init_module() is called by the kernel when kerneld loads the module in * memory. Here is the real beginning of the code. * . cleanup_module() is called by the kernel when kerneld removes the module */#if (LINUX_VERSION_CODE > (2*65536 + 256 + 17))EXPORT_NO_SYMBOLS;MODULE_AUTHOR("Martin von L鰓is");/* no supported device *//* no parameters */#endifint init_module(void){ int error = init_ntfs_fs();#if (LINUX_VERSION_CODE < (2*65536 + 256 + 18)) if(!error) register_symtab(0);#endif return error;}void cleanup_module(void){ NTFS_DEBUG("unregistering %s\n",ntfs_fs_type.name); unregister_filesystem(&ntfs_fs_type);}#endif/* These functions allow the rest of the ntfs code some generic interface to the operating system */static char print_buf[1024];void ntfs_error(const char *fmt,...){ va_list ap; va_start(ap,fmt); strcpy(print_buf,KERN_ERR); vsprintf(print_buf+3,fmt,ap); printk(print_buf); va_end(ap);}void ntfs_debug(const char *fmt,...){#ifdef DEBUG va_list ap; if(ntdebug & DEBUG_OTHER){ va_start(ap,fmt); strcpy(print_buf,KERN_DEBUG); vsprintf(print_buf+3,fmt,ap); printk(print_buf); va_end(ap); }#endif}void *ntfs_malloc(int size){ void *ret=kmalloc(size,GFP_KERNEL); if(ntdebug & DEBUG_MALLOC){ NTFS_DEBUG("Allocating %x at %x\n",size,(unsigned)ret); } return ret;}void ntfs_free(void *block){ if(ntdebug & DEBUG_MALLOC){ NTFS_DEBUG("Releasing memory at %x\n",(unsigned)block); } kfree(block);}int ntfs_getput_clusters(ntfs_volume *vol,int cluster, ntfs_size_t start_offs, ntfs_size_t length,ntfs_io *buf){ struct super_block *sb=NTFS_SB(vol); struct buffer_head *bh; ntfs_size_t to_copy; if(buf->do_read) NTFS_DEBUG("get_clusters %d %d %d\n",cluster,start_offs,length); else NTFS_DEBUG("put_clusters %d %d %d\n",cluster,start_offs,length); while(length) { if(!(bh=bread(sb->s_dev,cluster,vol->clustersize))) { NTFS_DEBUG("%s failed\n", buf->do_read?"Reading":"Writing"); return 0; } to_copy=min(vol->clustersize-start_offs,length); lock_buffer(bh); if(buf->do_read) buf->fn_put(buf,bh->b_data+start_offs,to_copy); else { buf->fn_get(bh->b_data+start_offs,buf,to_copy); mark_buffer_dirty(bh,1); } unlock_buffer(bh); length-=to_copy; start_offs=0; cluster++; brelse(bh); } return 1;}int ntfs_read_mft_record(ntfs_volume *vol,int mftno,char *buf){ ntfs_io io; NTFS_DEBUG("read_mft_record %x\n",mftno); if(mftno==FILE_MFT) { memcpy(buf,vol->mft,vol->mft_recordsize); return 0; } if(!vol->mft_ino) { printk("ntfs:something is terribly wrong here\n"); return -1; } io.fn_put=ntfs_put; io.fn_get=0; io.param=buf; if(ntfs_read_attr(vol->mft_ino,AT_DATA,NULL,mftno*vol->mft_recordsize, &io,vol->mft_recordsize)!=vol->mft_recordsize) { NTFS_DEBUG("read_mft_record: read %x failed\n",mftno); return -1; } NTFS_DEBUG("read_mft_record: finished read %x\n",mftno); if(!ntfs_check_mft_record(vol,buf)) { printk("Invalid MFT record for %x\n",mftno); return -1; } NTFS_DEBUG("read_mft_record: Done %x\n",mftno); return 0;}ntfs_time64_t ntfs_now(){ return ntfs_unixutc2ntutc(CURRENT_TIME);}/* * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -