您的位置:首页 > 运维架构 > Linux

Linux 访问fat格式文件系统

2010-05-23 12:22 309 查看
#ifndef __KERNEL__

# define __KERNEL__

#endif

#ifndef MODULE

# define MODULE

#endif

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <asm/uaccess.h>

#include <linux/moduleparam.h>

#include <linux/sched.h>

#include <asm/unistd.h>

#include <linux/fs.h>

#include <linux/dcache.h>

#include <linux/mount.h>

#include <linux/file.h>

#include <linux/fs_struct.h>

#include <linux/msdos_fs.h>

#ifdef CONFIG_SMP

#define __SMP__

#endif

/*

系统调用号的定义在 /usr/include/asm/unistd.h 文件中

printk结果通过dmesg查看。

可以用cat /boot/System.map-`uname -r` |grep sys_call_table 查看table的地址

*/

#define __NR_get_FAT_boot 39

#define __NR_get_FAT_dir 15 //替换chmod系统调用

unsigned long **sys_call_table;//调用表

unsigned long * savedcall; //存放被替换的调用指针

struct idt_tag

{

unsigned short offset_low,segment_select;

unsigned char reserved,flags;

unsigned short offset_high;

};

asmlinkage long testsyscall(char *buf)//测试系统调用

{

printk("hello world/n");

char* b="hello world/n";

int n=copy_to_user(buf,b,strlen(b));

printk("复制成功/n");

return n;

}

asmlinkage long get_files_info(char * filesystem_type)//取得当前目录的文件系统信息

{

struct fs_struct *fs ;

struct vfsmount *mnt ;

struct super_block *mnt_sb ;

struct file_system_type *s_type;

read_lock(¤t->fs->lock);

fs = current->fs;

mnt = fs->pwdmnt;

mnt_sb = mnt-> mnt_sb ;

s_type = mnt_sb -> s_type;

printk("PWD Filesystem Type is : %s/n",s_type->name);

copy_to_user(filesystem_type,s_type->name,strlen(s_type->name));

printk("PWD= %ld/n",mnt_sb->s_blocksize);

read_unlock(¤t->fs->lock);

return 0;

}

/*
http://linux.chinaunix.net/bbs/viewthread.php?tid=916894&rpid=6437642&ordertype=0&page=1#pid6437642
//fat_boot_sector是一个定义在include/linux/msdos_fs.h中的结构体。

//它的内容结构和磁盘中的super block完全一样。所有可用直接赋值,这样变量b

//就有了这个设备的SB信息。

b = (struct fat_boot_sector *) bh->b_data;

/home/god/linux-2.6.24/include/linux

*/

/*get_FAT_boot*/

asmlinkage long get_FAT_boot(char * filesystem_type)//取得fat文件系统的信息

{

struct fs_struct *fs ;

struct vfsmount *mnt ;

struct super_block *mnt_sb ;

struct buffer_head * bh=NULL;

struct fat_boot_sector *fat_sector;

char c[512];

int len;

read_lock(¤t->fs->lock);

fs = current->fs;

mnt = fs->pwdmnt;

mnt_sb = mnt-> mnt_sb ;

char *fsname=mnt_sb -> s_type->name;

char *sfs="vfat";

if(strcmp(fsname,sfs)==0)//此时文件系统是vfat

{

sb_min_blocksize(mnt_sb, 512);

bh = sb_bread(mnt_sb, 0);

if(bh!=NULL)

{

fat_sector=(struct fat_boot_sector *)bh->b_data;

len=sprintf(c,"FAT文件系统具体参数如下:/n");

len=sprintf(c,"%sbackup boot sector= %d/n",c,fat_sector->backup_boot);

len=sprintf(c,"%ssectors/cluster= %d/n",c,fat_sector->sec_per_clus);

len=sprintf(c,"%snumber of heads= %d/n",c,fat_sector->heads);

len=sprintf(c,"%shidden sectors (unused)= %d/n",c,fat_sector->hidden);

len=sprintf(c,"%smedia code= %d/n",c,fat_sector->media);

len=sprintf(c,"%sbytes per logical sector= %d/n",c,(fat_sector->sector_size[1]<<8)+fat_sector->sector_size[0]);

}

else

len=sprintf(c,"BH is wrong!!");

}

else//此时文件系统不是vfat

len=sprintf(c,"Wrong !! The filesystem is %s!!/n",fsname);

c[len]='/0';

len++;

copy_to_user(filesystem_type,c,len);

read_unlock(¤t->fs->lock);

return len;

}

/*http://linux.chinaunix.net/bbs/thread-916894-1-1.html*/

/*目录文件的目录项在内核中用struct msdos_dir_entry(定义在 include/linux/msdos_fs.h中)来表示*/

/*可见这个数据结构与磁盘中的目录项基本一致*/

/*http://blog.chinaunix.net/u2/87570/showart_2126000.html*/

static bool isEmpty(unsigned char c)

{

if(c==0x00||c==0xE5)

return true;

else

return false;

}

static void memswap(unsigned char *dest,unsigned char *src, int count){//交换两块内存

int i=0;

unsigned char t;

while(i<count)

{

t=dest[i];

dest[i]=src[i];

src[i]=t;

i++;

}

}

/*get_FAT_dir*/

asmlinkage long get_FAT_dir(char * filesystem_type)//取得fat文件系统的目录信息

{

struct fs_struct *fs ;

struct vfsmount *mnt ;//当前挂载点

struct file_system_type *s_type;

//struct dentry *pwdentry;//当前目录项

struct super_block *mnt_sb ;

// struct inode *inode;

//struct list_head d_subdirs;

struct dentry *cpwd;

struct inode *ci;

struct msdos_sb_info * dos_sb;

struct msdos_dir_entry *dos_de;

struct msdos_inode_info *dos_si;

struct fat_boot_sector *fbs;

struct buffer_head *bh=NULL;

struct msdos_dir_entry *dir0,*dir1;

int len;

len=0;

char c[2048];

len=sprintf(c,"当前目录信息如下:/n");

read_lock(¤t->fs->lock);

fs = current->fs;

mnt = fs->pwdmnt;

mnt_sb = mnt-> mnt_sb ;

s_type = mnt_sb -> s_type;

cpwd = fs->pwd;

ci = cpwd->d_inode;

mnt_sb = ci->i_sb;

char *fsname=s_type->name;

char *sfs="vfat";

if(strcmp(fsname,sfs)==0)//此时文件系统是vfat

{

/* len=sprintf(c,"当前目录下的信息为:/n");*/

/* struct dentry *p;*/

/* list_for_each(p,d_subdirs)*/

/* {*/

/* len=sprintf(c,"%s目录 %p/n",c,p);*/

/* }*/

dos_sb = (struct msdos_sb_info *)mnt_sb->s_fs_info;

len=sprintf(c,"%s每簇扇数=%d/n",c,dos_sb->sec_per_clus);

len=sprintf(c,"%s簇大小=%d/n",c,dos_sb->cluster_size);

len=sprintf(c,"%sFAT位数=%d/n",c,dos_sb->fat_bits);

len=sprintf(c,"%sFAT开始扇=%d/n",c,dos_sb->fat_start);

len=sprintf(c,"%sFAT长度=%ld/n",c,dos_sb->fat_length);

len=sprintf(c,"%s目录开始扇=%ld/n",c,dos_sb->dir_start);

len=sprintf(c,"%s目录入口=%d/n",c,dos_sb->dir_entries);

len=sprintf(c,"%s数据开始扇=%ld/n",c,dos_sb->data_start);

len=sprintf(c,"%s最大簇号=%ld/n",c,dos_sb->max_cluster);

len=sprintf(c,"%s根开始扇=%ld/n",c,dos_sb->root_cluster);

dos_si = container_of(ci, struct msdos_inode_info, vfs_inode);

bh = sb_bread(mnt_sb, 0);

if(bh == NULL) {

printk(KERN_ERR "Boot failed/n");

}

fbs = (struct fat_boot_sector *)(bh->b_data);

len=sprintf(c,"%s系统信息=%s/n/n",c,fbs->system_id);

bh = sb_bread(mnt_sb, dos_sb->dir_start);//根据目录开始扇地址读出目录项

if (bh == NULL) {

printk(KERN_ERR "FAT: Directory bread failed/n");

}

len=sprintf(c,"%s##整理前##/n",c);

dos_de = (struct msdos_dir_entry *)(bh->b_data);

int i=0;

for(i=0; i<16; i++)

{

len=sprintf(c,"%s %d=%s/n",c,i,dos_de->name+ i*sizeof(struct msdos_dir_entry));

printk("%d=%s/n",i,dos_de->name+ i*sizeof(struct msdos_dir_entry));

}

/*

重新排序整理过程

*/

unsigned char head,tail;//存放两头的结构的名字首字符

int j=15;

i=0;

dir0=NULL;

dir1=NULL;

while(i < j){

if(dir0==NULL)

dir0 =(struct msdos_dir_entry*)(bh->b_data + i*sizeof(struct msdos_dir_entry));

if(dir1==NULL)

dir1 =(struct msdos_dir_entry*)(bh->b_data + j*sizeof(struct msdos_dir_entry));

head = dir0->name[0];

tail = dir1->name[0];

if(isEmpty(head)&&!isEmpty(tail))//前空后满则直接跳过

{

i++;

j--;

dir0=NULL;

dir1=NULL;

printk("i++=%d,j--=%d/n",i,j);

}

else if(isEmpty(head)&&isEmpty(tail))//前空后空则跳过前

{

i++;

dir0=NULL;

printk("i++=%d,j=%d/n",i,j);

}

else if(!isEmpty(head)&&!isEmpty(tail))//前满后满则跳过后

{

j--;

dir1=NULL;

printk("i=%d,j--=%d/n",i,j);

}

else if(!isEmpty(head)&&isEmpty(tail))//前满后空则交换两块内存

{

memswap((unsigned char*)dir0,(unsigned char*)dir1,sizeof(struct msdos_dir_entry));//交换内存

i++;

j--;

dir0=NULL;

dir1=NULL;

printk("交换后 i++=%d,j--=%d/n",i,j);

}

}

len=sprintf(c,"%s##整理后##/n",c);

i=0;

while(i < 16){

len=sprintf(c,"%s %d :%s/t",c,i,dos_de->name+ i*sizeof(struct msdos_dir_entry));

head = (dos_de->name+ i*sizeof(struct msdos_dir_entry))[0];

if(head == 0xE5){

len+=sprintf(c+len,"E5已删除/n");

}else if(head == 0x00){

len+=sprintf(c+len,"00未用/n");

}else{

len+=sprintf(c+len,"已用/n");

}

i++;

}

}

else//此时文件系统是vfat

len=sprintf(c,"Wrong !! The filesystem is %s!!/n",fsname);

c[len]='/0';

len++;

printk("/nLen= %d/n/n",len);

copy_to_user(filesystem_type,c,len);

read_unlock(¤t->fs->lock);

return len;

}

static unsigned long getSyscallTable(void)

{

unsigned char idtr[6],*shell,*sort;

struct idt_tag *idt;

unsigned long system_call,sct;

unsigned short offset_low,offset_high;

char *p;

int i;

__asm__("sidt %0":"=m"(idtr));

idt = (struct idt_tag*)((*(unsigned long*)&idtr[2]) + 8 * 0x80);

offset_low = idt->offset_low;

offset_high = idt->offset_high;

system_call = (offset_high)<<16 | offset_low;

shell = (char*)system_call;

sort = "/xff/x14/x85";

for(i = 0;i < 100-2;i++)

if(shell [ i ] == sort[0] && shell[i+1] == sort[1] && shell[i+2] == sort[2])

break;

p = &shell [ i ] + 3;

sct = *(unsigned long*)p;

return sct;

}

int init_module(void)

{

sys_call_table = (unsigned long**)getSyscallTable();

printk("/n*********************************/n");

printk("系统调用表的首地址为%p/n",sys_call_table);

savedcall=sys_call_table[__NR_get_FAT_boot];//保存原来的调用

printk("原来的%d系统调用为: %p/n",__NR_get_FAT_boot,savedcall);

printk("目的系统调用为%p/n",(unsigned long*)get_FAT_dir);

sys_call_table[__NR_get_FAT_boot]=(unsigned long*)get_FAT_dir;

printk("更改后的%d系统调用为: %p/n",__NR_get_FAT_boot,sys_call_table[__NR_get_FAT_boot]);

printk("loaded success /n");

return 0;

}

void cleanup_module(void)

{

printk("恢复前的%d系统调用为: %p/n",__NR_get_FAT_boot,sys_call_table[__NR_get_FAT_boot]);

sys_call_table[__NR_get_FAT_boot]=savedcall;

printk("恢复后的%d系统调用为: %p/n",__NR_get_FAT_boot,sys_call_table[__NR_get_FAT_boot]);

printk("unloaded success/n");

}

MODULE_LICENSE("GPL");

MODULE_AUTHOR("QCH");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: