Linux 访问fat格式文件系统

时间:2022-02-19 16:05:24

#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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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");