📄 fs.c
字号:
r->u.generic_ip = ino;#endif error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len, ino); if(error) goto out; r->i_uid = vol->uid; r->i_gid = vol->gid; r->i_nlink = 1; r->i_sb = dir->i_sb; si = ntfs_find_attr(ino,vol->at_standard_information,NULL); if(si){ char *attr = si->d.data; r->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); r->i_ctime = ntfs_ntutc2unixutc(NTFS_GETU64(attr)); r->i_mtime = ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); } /* It's a directory */ r->i_op = &ntfs_dir_inode_operations; r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;#ifdef CONFIG_NTFS_RW r->i_mode|=S_IWUGO;#endif r->i_mode &= ~vol->umask; insert_inode_hash(r); d_instantiate(d, r); error = 0; out: ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error); return -error;}#endifstatic int ntfs_bmap(struct inode *ino,int block){ int ret=ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino),block); ntfs_debug(DEBUG_OTHER, "bmap of %lx,block %x is %x\n", ino->i_ino,block,ret); return (ret==-1) ? 0:ret;}static struct file_operations ntfs_file_operations = { NULL, /* lseek */ ntfs_read,#ifdef CONFIG_NTFS_RW ntfs_write,#else NULL,#endif NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ generic_file_mmap, NULL, /* open */ NULL, /* flush */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL, /* revalidate */ NULL, /* lock */};static 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 */ generic_readpage, NULL, /* writepage */ ntfs_bmap, NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ NULL, /* updatepage */ NULL, /* revalidate */};static struct file_operations ntfs_dir_operations = { NULL, /* lseek */ NULL, /* read */ NULL, /* write */ ntfs_readdir, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ NULL, /* flush */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL, /* revalidate */ NULL, /* lock */};static struct inode_operations ntfs_dir_inode_operations = { &ntfs_dir_operations,#ifdef CONFIG_NTFS_RW ntfs_create, /* create */#else NULL,#endif ntfs_lookup, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */#ifdef CONFIG_NTFS_RW _linux_ntfs_mkdir, /* mkdir */#else NULL,#endif NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ NULL, /* updatepage */ NULL, /* revalidate */};/* ntfs_read_inode is called by the Virtual File System (the kernel layer that * deals with filesystems) when iget is called requesting an inode not already * present in the inode table. Typically filesystems have separate * inode_operations for directories, files and symlinks. */static void ntfs_read_inode(struct inode* inode){ ntfs_volume *vol; int can_mmap=0; ntfs_inode *ino; ntfs_attribute *data; ntfs_attribute *si; vol=NTFS_INO2VOL(inode); inode->i_op=NULL; inode->i_mode=0; ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino); switch(inode->i_ino) { /* those are loaded special files */ case FILE_MFT: ntfs_error("Trying to open MFT\n");return; default: #ifdef NTFS_IN_LINUX_KERNEL ino=&inode->u.ntfs_i; #else /* FIXME: check for ntfs_malloc failure */ ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); inode->u.generic_ip=ino; #endif if(!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),inode->i_ino)) { ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n", (unsigned int)inode->i_ino); return; } } /* Set uid/gid from mount options */ inode->i_uid=vol->uid; inode->i_gid=vol->gid; inode->i_nlink=1; /* Use the size of the data attribute as file size */ data = ntfs_find_attr(ino,vol->at_data,NULL); if(!data) { inode->i_size=0; can_mmap=0; } else { inode->i_size=data->size; can_mmap=!data->resident && !data->compressed; } /* get the file modification times from the standard information */ si=ntfs_find_attr(ino,vol->at_standard_information,NULL); if(si){ char *attr=si->d.data; inode->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); inode->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr)); inode->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); } /* if it has an index root, it's a directory */ if(ntfs_find_attr(ino,vol->at_index_root,"$I30")) { ntfs_attribute *at; at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30"); inode->i_size = at ? at->size : 0; inode->i_op=&ntfs_dir_inode_operations; inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO; } else { inode->i_op=can_mmap ? &ntfs_inode_operations : &ntfs_inode_operations_nobmap; inode->i_mode=S_IFREG|S_IRUGO; }#ifdef CONFIG_NTFS_RW if(!data || !data->compressed) inode->i_mode|=S_IWUGO;#endif inode->i_mode &= ~vol->umask;}#ifdef CONFIG_NTFS_RWstatic void ntfs_write_inode (struct inode *ino){ ntfs_debug (DEBUG_LINUX, "ntfs:write inode %x\n", ino->i_ino); ntfs_update_inode (NTFS_LINO2NINO (ino));}#endifstatic void _ntfs_clear_inode(struct inode *ino){ ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n",ino->i_ino);#ifdef NTFS_IN_LINUX_KERNEL if(ino->i_ino!=FILE_MFT) ntfs_clear_inode(&ino->u.ntfs_i);#else if(ino->i_ino!=FILE_MFT && ino->u.generic_ip) { ntfs_clear_inode(ino->u.generic_ip); ntfs_free(ino->u.generic_ip); ino->u.generic_ip=0; }#endif return;}/* Called when umounting a filesystem by do_umount() in fs/super.c */static void ntfs_put_super(struct super_block *sb){ ntfs_volume *vol; ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n"); vol=NTFS_SB2VOL(sb); ntfs_release_volume(vol); if(vol->nls_map) unload_nls(vol->nls_map);#ifndef NTFS_IN_LINUX_KERNEL ntfs_free(vol);#endif ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n"); MOD_DEC_USE_COUNT;}/* Called by the kernel when asking for stats */static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize){ struct statfs fs; struct inode *mft; ntfs_volume *vol; int error; ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n"); vol=NTFS_SB2VOL(sb); memset(&fs,0,sizeof(fs)); fs.f_type=NTFS_SUPER_MAGIC; fs.f_bsize=vol->clustersize; error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks ); if( error ) return error; fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap); fs.f_bavail=fs.f_bfree; /* Number of files is limited by free space only, so we lie here */ fs.f_ffree=0; mft=iget(sb,FILE_MFT); fs.f_files=mft->i_size/vol->mft_recordsize; iput(mft); /* should be read from volume */ fs.f_namelen=255; copy_to_user(sf,&fs,bufsize); return 0;}/* Called when remounting a filesystem by do_remount_sb() in fs/super.c */static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options){ if(!parse_options(NTFS_SB2VOL(sb), options)) return -EINVAL; return 0;}/* Define the super block operation that are implemented */static struct super_operations ntfs_super_operations = { ntfs_read_inode,#ifdef CONFIG_NTFS_RW ntfs_write_inode,#else NULL,#endif NULL, /* put_inode */ NULL, /* delete_inode */ NULL, /* notify_change */ ntfs_put_super, NULL, /* write_super */ ntfs_statfs, ntfs_remount_fs, /* remount */ _ntfs_clear_inode, /* clear_inode */ };/* Called to mount a filesystem by read_super() in fs/super.c * Return a super block, the main structure of a filesystem * * NOTE : Don't store a pointer to an option, as the page containing the * options is freed after ntfs_read_super() returns. * * NOTE : A context switch can happen in kernel code only if the code blocks * (= calls schedule() in kernel/sched.c). */struct super_block * ntfs_read_super(struct super_block *sb, void *options, int silent){ ntfs_volume *vol; struct buffer_head *bh; int i; /* When the driver is compiled as a module, kmod must know when it * can safely remove it from memory. To do this, each module owns a * reference counter. */ MOD_INC_USE_COUNT; /* Don't put ntfs_debug() before MOD_INC_USE_COUNT, printk() can block * so this could lead to a race condition with kmod. */ ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");#ifdef NTFS_IN_LINUX_KERNEL vol = NTFS_SB2VOL(sb);#else if(!(vol = ntfs_malloc(sizeof(ntfs_volume)))) goto ntfs_read_super_dec; NTFS_SB2VOL(sb)=vol;#endif if(!parse_options(vol,(char*)options)) goto ntfs_read_super_vol; /* Ensure that the super block won't be used until it is completed */ lock_super(sb); ntfs_debug(DEBUG_OTHER, "lock_super\n");#if 0 /* Set to read only, user option might reset it */ sb->s_flags |= MS_RDONLY;#endif /* Assume a 512 bytes block device for now */ set_blocksize(sb->s_dev, 512); /* Read the super block (boot block) */ if(!(bh=bread(sb->s_dev,0,512))) { ntfs_error("Reading super block failed\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); /* Check for 'NTFS' magic number */ if(!IS_NTFS_VOLUME(bh->b_data)){ ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); brelse(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); ntfs_init_volume(vol,bh->b_data); ntfs_debug(DEBUG_OTHER, "MFT record at cluster 0x%X\n",vol->mft_cluster); brelse(bh); NTFS_SB(vol)=sb; ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); /* Inform the kernel that a device block is a NTFS cluster */ sb->s_blocksize=vol->clustersize; for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i != 1;i>>=1) sb->s_blocksize_bits++; set_blocksize(sb->s_dev,sb->s_blocksize); ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); /* Allocate a MFT record (MFT record can be smaller than a cluster) */ if(!(vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize)))) goto ntfs_read_super_unl; /* Read at least the MFT record for $MFT */ for(i=0;i<max(vol->mft_clusters_per_record,1);i++){ if(!(bh=bread(sb->s_dev,vol->mft_cluster+i,vol->clustersize))) { ntfs_error("Could not read MFT record 0\n"); goto ntfs_read_super_mft; } ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize); brelse(bh); ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i); } /* Check and fixup this MFT record */ if(!ntfs_check_mft_record(vol,vol->mft)){ ntfs_error("Invalid MFT record 0\n"); goto ntfs_read_super_mft; } /* Inform the kernel about which super operations are available */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); if(ntfs_load_special_files(vol)){ ntfs_error("Error loading special files\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); /* Get the root directory */ if(!(sb->s_root=d_alloc_root(iget(sb,FILE_ROOT),NULL))){ ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } unlock_super(sb); ntfs_debug(DEBUG_OTHER, "unlock_super\n"); ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb;ntfs_read_super_mft: ntfs_free(vol->mft);ntfs_read_super_unl: sb->s_dev = 0; unlock_super(sb); ntfs_debug(DEBUG_OTHER, "unlock_super\n");ntfs_read_super_vol: #ifndef NTFS_IN_LINUX_KERNEL ntfs_free(vol);ntfs_read_super_dec: #endif ntfs_debug(DEBUG_OTHER, "read_super: done\n"); MOD_DEC_USE_COUNT; return NULL;}/* Define the filesystem * * Define SECOND if you cannot unload ntfs, and want to avoid rebooting * for just one more test */static struct file_system_type ntfs_fs_type = {/* Filesystem name, as used after mount -t */#ifndef SECOND "ntfs",#else "ntfs2",#endif/* This filesystem requires a device (a hard disk) * May want to add FS_IBASKET when it works */ FS_REQUIRES_DEV,/* Entry point of the filesystem */ ntfs_read_super,/* Will point to the next filesystem in the kernel table */ NULL};/* When this code is not compiled as a module, this is the main entry point, * called by do_sys_setup() in fs/filesystems.c * * NOTE : __initfunc() is a macro used to remove this function from memory * once initialization is done */__initfunc(int init_ntfs_fs(void)){ /* Comment this if you trust klogd. There are reasons not to trust it */#if defined(DEBUG) && !defined(MODULE) extern int console_loglevel; console_loglevel=15;#endif printk(KERN_NOTICE "NTFS version " NTFS_VERSION "\n"); SYSCTL(1); ntfs_debug(DEBUG_OTHER, "registering %s\n",ntfs_fs_type.name); /* add this filesystem to the kernel table of filesystems */ return register_filesystem(&ntfs_fs_type);}#ifdef MODULE/* A module is a piece of code which can be inserted in and removed * from the running kernel whenever you want using lsmod, or on demand using * kmod *//* No function of this module is needed by another module */EXPORT_NO_SYMBOLS;/* Only used for documentation purposes at the moment, * see include/linux/module.h */MODULE_AUTHOR("Martin von L鰓is");MODULE_DESCRIPTION("NTFS driver");/* no MODULE_SUPPORTED_DEVICE() *//* Load-time parameter */MODULE_PARM(ntdebug, "i");MODULE_PARM_DESC(ntdebug, "Debug level");/* When this code is compiled as a module, if you use mount -t ntfs when no * ntfs filesystem is registered (see /proc/filesystems), get_fs_type() in * fs/super.c asks kmod to load the module named ntfs in memory. * * Therefore, this function is the main entry point in this case */int init_module(void){ return init_ntfs_fs();}/* Called by kmod just before the kernel removes the module from memory */void cleanup_module(void){ SYSCTL(0); ntfs_debug(DEBUG_OTHER, "unregistering %s\n",ntfs_fs_type.name); unregister_filesystem(&ntfs_fs_type);}#endif/* * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -