📄 fs.c
字号:
ino->i_ino,block,ret); return (ret==-1) ? 0:ret;}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, /* 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_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,#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,#else NULL, /* mkdir */#endif NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */};/* 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; inode->u.generic_ip=NULL; 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: ino=NTFS_INO2VOL(inode)->mft_ino;break; default: ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); 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; } } inode->u.generic_ip=ino; /* 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|S_IMMUTABLE; inode->i_mode=S_IFREG|S_IRUGO; }#ifdef CONFIG_NTFS_RW inode->i_mode |= S_IWUGO;#endif inode->i_mode &= ~vol->umask;}static void ntfs_put_inode(struct inode *ino){ ntfs_debug(DEBUG_OTHER, "ntfs_put_inode %lx\n",ino->i_ino); 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; } clear_inode(ino);}static void ntfs_put_super(struct super_block *sb){ ntfs_volume *vol=NTFS_SB2VOL(sb); ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n"); lock_super(sb); ntfs_release_volume(vol); sb->s_dev=0; ntfs_free(sb->u.generic_sbp); sb->u.generic_sbp=0; unlock_super(sb); MOD_DEC_USE_COUNT;}static void ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize){ struct statfs fs; struct inode *mft; ntfs_volume *vol; 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; if(ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks )) return; 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; memcpy_tofs(sf,&fs,bufsize);}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;}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 */};/* Entry point of the filesystem. It is called after when the filesystem is * mounted. Don't use any pointer into options, as the page containing is is * freed after ntfs_read_super returns. */struct super_block * ntfs_read_super(struct super_block *sb, void *options, int silent){ struct buffer_head *bh; int dev=sb->s_dev; int i; ntfs_volume *vol;#if defined(DEBUG) && !defined(MODULE) extern int console_loglevel; console_loglevel=15;#endif ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); MOD_INC_USE_COUNT; lock_super(sb); ntfs_debug(DEBUG_OTHER, "lock_super\n");#ifndef CONFIG_NTFS_RW /* set to read only, user option might reset it */ sb->s_flags |= MS_RDONLY;#endif vol=ntfs_malloc(sizeof(ntfs_volume)); if(!parse_options(sb,vol,(char*)options)){ unlock_super(sb); ntfs_free(vol); 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(DEBUG_OTHER, "Done reading boot block\n"); /* Check for 'NTFS' magic at offset 3 */ if(!IS_NTFS_VOLUME(bh->b_data)){ ntfs_debug(DEBUG_OTHER, "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(DEBUG_OTHER, "Going to init volume\n"); ntfs_init_volume(vol,bh->b_data); NTFS_SB(vol)=sb; NTFS_SB2VOL(sb)=vol; ntfs_debug(DEBUG_OTHER, "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(DEBUG_OTHER, "set_blocksize\n"); ntfs_debug(DEBUG_OTHER, "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_error("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(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i); } /* Check and fixup MFT record 0 */ if(!ntfs_check_mft_record(vol,vol->mft)){ ntfs_error("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(DEBUG_OTHER, "Reading master and upcase files\n"); if(ntfs_load_special_files(vol)){ ntfs_error("Error loading special files\n"); sb->s_dev=0; unlock_super(sb); MOD_DEC_USE_COUNT; return NULL; } unlock_super(sb); ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); /* get the root directory */ if(!(sb->s_mounted=iget(sb,FILE_ROOT))){ sb->s_dev=0; ntfs_debug(DEBUG_OTHER, "Could not get root dir inode\n"); MOD_DEC_USE_COUNT; return NULL; } ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb;}/* 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 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/* 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 */int init_module(void){ return init_ntfs_fs();}void cleanup_module(void){ SYSCTL(0); ntfs_debug(DEBUG_OTHER, "unregistering %s\n",ntfs_fs_type.name); unregister_filesystem(&ntfs_fs_type);}#endif#ifdef MODULE/* this is copied from linux/kernel/sysctl.c, because Linux 2.0 fails to export it */int proc_dointvec(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp){ int *i, vleft, first=1, len, left, neg, val; #define TMPBUFLEN 20 char buf[TMPBUFLEN], *p; if (!table->data || !table->maxlen || !*lenp || (filp->f_pos && !write)) { *lenp = 0; return 0; } i = (int *) table->data; vleft = table->maxlen / sizeof(int); left = *lenp; for (; left && vleft--; i++, first=0) { if (write) { while (left && isspace(get_user((char *) buffer))) left--, ((char *) buffer)++; if (!left) break; neg = 0; len = left; if (len > TMPBUFLEN-1) len = TMPBUFLEN-1; memcpy_fromfs(buf, buffer, len); buf[len] = 0; p = buf; if (*p == '-' && left > 1) { neg = 1; left--, p++; } if (*p < '0' || *p > '9') break; val = simple_strtoul(p, &p, 0); len = p-buf; if ((len < left) && *p && !isspace(*p)) break; if (neg) val = -val; buffer += len; left -= len; *i = val; } else { p = buf; if (!first) *p++ = '\t'; sprintf(p, "%d", *i); len = strlen(buf); if (len > left) len = left; memcpy_tofs(buffer, buf, len); left -= len; buffer += len; } } if (!write && !first && left) { put_user('\n', (char *) buffer); left--, buffer++; } if (write) { p = (char *) buffer; while (left && isspace(get_user(p++))) left--; } if (write && first) return -EINVAL; *lenp -= left; filp->f_pos += *lenp; return 0;}#endif/* * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -