Linux下简单的mount命令实现--使用hexdump 查看文件系统(自动识别文件系统类型)

背景简述
mount()/umount()为Linux下挂载和卸载磁盘分区的系统调用,函数原型分别如下:

int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags, const void *data);

int umount(const char *target);

mount()的filesystemtype这个参数需要填入需要挂载的磁盘分区的文件系统类型,比如需要挂载fat32,那么这个参数需要填写为“vfat”,分区文件系统类型为ext2,需要填写为“ext2”;如果挂载成功,返回0,挂载失败,返回-1,如果不指定挂载类型,系统就会自动探测分区类型并挂载,有可能会失败;

所以,这就需要我们获取当前要挂载的磁盘分区的文件系统类型;在shell上我们可以通过fdisk /dev/sda 这样类似的命令,然后敲p打印出现当前的磁盘分区信息,但是如果想直接通过函数调用的方式获取(非system()系统调用),还得另外找办法;

hexdump读取分区信息
我们利用hexdump这个工具,分别读取ext2/fat32/ntfs分区的信息,如下方法:

hexdump读fat32分区:

hexdump -C -n 256 sda1

00000000 eb fe 90 4d 53 44 4f 53 35 2e 30 00 02 10 20 00 |…MSDOS5.0… .|
00000010 02 00 00 00 00 f8 00 00 3f 00 ff 00 00 00 00 00 |…?..|
00000020 e0 d7 d2 01 54 3a 00 00 00 00 00 00 02 00 00 00 |…T:…|
00000030 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…|
00000040 00 01 29 76 6d 01 00 4e 4f 20 4e 41 4d 45 20 20 |…)vm…NO NAME |
00000050 20 20 46 41 54 33 32 20 20 20 00 00 00 00 00 00 | FAT32 …|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…|

有看到0x52 Offset开始的位置有字符串“FAT32”;

hexdump读ntfs分区:

hexdump -C -n 256 /dev/sda2

00000000 eb 52 90 4e 54 46 53 20 20 20 20 00 02 08 00 00 |.R.NTFS …|
00000010 00 00 00 00 00 f8 00 00 3f 00 ff 00 20 00 00 00 |…?.. …|
00000020 00 00 00 00 80 00 00 00 df 3f 19 01 00 00 00 00 |…?..|
00000030 00 00 0c 00 00 00 00 00 02 00 00 00 00 00 00 00 |…|
00000040 f6 00 00 00 01 00 00 00 6d 8e f9 6c b3 f9 6c 96 |…m…l…l.|
00000050 00 00 00 00 fa 33 c0 8e d0 bc 00 7c fb 68 c0 07 |…3…|.h…|
00000060 1f 1e 68 66 00 cb 88 16 0e 00 66 81 3e 03 00 4e |…hf…f.>…N|
00000070 54 46 53 75 15 b4 41 bb aa 55 cd 13 72 0c 81 fb |TFSu…A…U…r…|
00000080 55 aa 75 06 f7 c1 01 00 75 03 e9 dd 00 1e 83 ec |U.u…u…|
00000090 18 68 1a 00 b4 48 8a 16 0e 00 8b f4 16 1f cd 13 |.h…H…|
000000a0 9f 83 c4 18 9e 58 1f 72 e1 3b 06 0b 00 75 db a3 |…X.r.;…u…|
000000b0 0f 00 c1 2e 0f 00 04 1e 5a 33 db b9 00 20 2b c8 |…Z3… +.|
000000c0 66 ff 06 11 00 03 16 0f 00 8e c2 ff 06 16 00 e8 |f…|
000000d0 4b 00 2b c8 77 ef b8 00 bb cd 1a 66 23 c0 75 2d |K.+.w…f#.u-|
000000e0 66 81 fb 54 43 50 41 75 24 81 f9 02 01 72 1e 16 |f…TCPAu$…r…|
000000f0 68 07 bb 16 68 70 0e 16 68 09 00 66 53 66 53 66 |h…hp…h…fSfSf|

在Offset ox3处有发现“NTFS”这样的字符串;

ext2/ext3格式不太一样,直接读前面256bytes读不到有特别能说明文件系统类型的字符串。有参考Linux 文件系统的 Superblock, Inode, Dentry 和 File这篇blog,这篇blog里面有详细描述Linux下ext2的Inode和Block,其中有superblock的说明,结构体类型如下:

struct ext3_super_block {
/00/ __u32 s_inodes_count; /* inodes 计数 /
__u32 s_blocks_count; /
blocks 计数 /
__u32 s_r_blocks_count; /
保留的 blocks 计数 /
__u32 s_free_blocks_count; /
空闲的 blocks 计数 /
/10/ __u32 s_free_inodes_count; /
空闲的 inodes 计数 /
__u32 s_first_data_block; /
第一个数据 block /
__u32 s_log_block_size; /
block 的大小 /
__s32 s_log_frag_size; /
可以忽略 /
/20/ __u32 s_blocks_per_group; /
每 block group 的 block 数量 /
__u32 s_frags_per_group; /
可以忽略 /
__u32 s_inodes_per_group; /
每 block group 的 inode 数量 /
__u32 s_mtime; /
Mount time /
/30/ __u32 s_wtime; /
Write time /
__u16 s_mnt_count; /
Mount count /
__s16 s_max_mnt_count; /
Maximal mount count /
__u16 s_magic; /
Magic 签名 /
__u16 s_state; /
File system state /
__u16 s_errors; /
Behaviour when detecting errors /
__u16 s_minor_rev_level; /
minor revision level /
/40/ __u32 s_lastcheck; /
time of last check /
__u32 s_checkinterval; /
max. time between checks /
__u32 s_creator_os; /
可以忽略 /
__u32 s_rev_level; /
Revision level /
/50/ __u16 s_def_resuid; /
Default uid for reserved blocks /
__u16 s_def_resgid; /
Default gid for reserved blocks /
__u32 s_first_ino; /
First non-reserved inode /
__u16 s_inode_size; /
size of inode structure /
__u16 s_block_group_nr; /
block group # of this superblock /
__u32 s_feature_compat; /
compatible feature set /
/60/ __u32 s_feature_incompat; /
incompatible feature set /
__u32 s_feature_ro_compat; /
readonly-compatible feature set /
/68/ __u8 s_uuid[16]; /
128-bit uuid for volume /
/78/ char s_volume_name[16]; /
volume name /
/88/ char s_last_mounted[64]; /
directory where last mounted /
/C8/ __u32 s_algorithm_usage_bitmap; /
可以忽略 /
__u8 s_prealloc_blocks; /
可以忽略 /
__u8 s_prealloc_dir_blocks; /
可以忽略 /
__u16 s_padding1; /
可以忽略 /
/D0/ __u8 s_journal_uuid[16]; /
uuid of journal superblock /
/E0/ __u32 s_journal_inum; /
日志文件的 inode 号数 /
__u32 s_journal_dev; /
日志文件的设备号 /
__u32 s_last_orphan; /
start of list of inodes to delete /
/EC/ __u32 s_reserved[197]; /
可以忽略 */
};

其中s_magic在ext2/ext3上固定为0xEF53。这个superblock放在分区的superblock1上(一个superblock大小为0x400bytes),所以可以通过s_magic去判定是否是ext2或者ext3,通过hexdump打印ext2的superblock1如下:

hexdump -C -n 1024 -s 1024 sda3

00000400 40 ce 08 00 fc 27 23 00 ff c1 01 00 71 9a 22 00 |@…’#…q.".|
00000410 33 ce 08 00 00 00 00 00 02 00 00 00 02 00 00 00 |3…|
00000420 00 80 00 00 00 80 00 00 c0 1f 00 00 78 40 ca 59 |…x@.Y|
00000430 5d 00 00 00 05 00 25 00 53 ef 00 00 01 00 00 00 |]…%.S…|
00000440 06 04 00 00 00 4e ed 00 00 00 00 00 01 00 00 00 |…N…|
00000450 00 00 00 00 0b 00 00 00 00 01 00 00 20 00 00 00 |… …|
00000460 02 00 00 00 01 00 00 00 14 1f 7f da 41 8f 46 fb |…A.F.|
00000470 81 ef 72 2e 2f fa db 25 00 00 00 00 00 00 00 00 |…r./…%…|
00000480 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…|
*
000004e0 00 00 00 00 00 00 00 00 00 00 00 00 9d f7 68 b5 |…h.|
000004f0 f1 14 44 86 93 ca 80 84 aa 93 05 41 01 00 00 00 |…D…A…|
00000500 00 00 00 00 00 00 00 00 06 04 00 00 00 00 00 00 |…|
00000510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…|
*
00000550 00 00 00 00 00 00 00 00 00 00 00 00 1c 00 1c 00 |…|
00000560 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…|
00000570 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…|

C实现获取文件系统类型
根据上面的实验结果,所实现的获取分区文件系统函数如下:

typedef enum
{
FS_NTFS,
FS_FAT32,
FS_EXT2,
FS_ERROR_TYPE,
}FILE_SYS_TYPE;
/**

  • [_getFSType get the filesystem type of partion]

  • @param devFD [the handle of usb partition device from open()]

  • @return [the filesystem type]
    /
    static FILE_SYS_TYPE _getFSType(int devFD)
    {
    unsigned char tmpBuffer[0x400];
    unsigned char
    pOffset = NULL;
    unsigned int readSize = 0;

    pOffset = &tmpBuffer[0];
    memset(pOffset, 0x00, 0x400);

    //read the tag data for ntfs/fat32
    readSize = read(devFD, pOffset, 0x100);
    if(!readSize)
    {
    printf(“read device file failed!\n”);
    return FS_ERROR_TYPE;
    }
    if(!memcmp((const void*)(pOffset+0x52), (const void*)“FAT32”, 5))//th offset with 0x52 is fat32 tag;
    {
    printf(“filesystem:fat32!\n”);
    return FS_FAT32;
    }
    else if(!memcmp((const void*)(pOffset+0x3), (const void*)“NTFS”, 4))//the offset with 0x3 is ntfs tag;
    {
    printf(“filesystem:ntfs!\n”);
    return FS_NTFS;
    }
    else
    {
    memset(pOffset, 0x00, 0x400);
    lseek(devFD,0x400, SEEK_SET); //seek to superblock1;
    readSize = read(devFD, pOffset, 0x400);//read the superblock1 to buffer;
    if(!readSize)
    {
    printf(“read1 device file failed!\n”);
    return FS_ERROR_TYPE;
    }

     pOffset = pOffset+0x38; //the offset 0x438 is the tag of ext2:0x53 0xef;
     if((pOffset[0] == 0x53) && (pOffset[1] == 0xef))
     {
         printf("filesystem:ext2 or ext3!\n");
         return FS_EXT2;
     }
     else
     {
         printf("the offset 0x438 vaule is:0x%x 0x%x!\n", pOffset[0], pOffset[1]);
     }
    

    }

    printf(“Unknown filesystem type!\n”);
    return FS_ERROR_TYPE;
    }

上面的函数要求传入分区对应的handle(用open()函数得到),然后返回文件系统类型;

测试函数
测试函数代码auto_mount.c如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/stat.h>
#include <fcntl.h>

/**

  • [main auto mount usb partions]

  • @param argc [the arguments number]

  • @param argv [the arguments pointer]

  • @return [the error code]
    */
    int main(int argc, char *argv[])
    {
    char devPath[512];
    char mountPath[512];

    int devFD = 0;
    int ret = -1;
    FILE_SYS_TYPE fsType = FS_ERROR_TYPE;

    if(argc != 3)
    {
    printf(“error paramter!\n”);
    return -1;
    }

    snprintf(devPath,511,"%s", argv[1]);
    snprintf(mountPath,511,"%s", argv[2]);
    printf(“devPath:%s, mountPath:%s\n”, devPath, mountPath);
    devFD = open(devPath, O_RDONLY);
    if(!devFD)
    {
    printf(“Open device failed!\n”);
    return -1;
    }
    fsType = _getFSType(devFD);
    printf(“fs type:%d\n”, fsType);

    switch(fsType)
    {
    case FS_EXT2:
    ret=mount((const char*)devPath, (const char*)mountPath, (const char*)“ext2”, 0, NULL);
    break;
    case FS_NTFS:
    ret=mount((const char*)devPath, (const char*)mountPath, (const char*)“ntfs3g”, 0, NULL);
    break;
    case FS_FAT32:
    ret=mount((const char*)devPath, (const char*)mountPath, (const char*)“vfat”, 0, NULL);
    break;
    default:
    printf(“Unknown filesystem type!\n”);
    }

    printf(“mount result:%d\n”, ret);
    close(devFD);
    return 0;
    }

测试函数可以如下方法编译:
gcc auto_mount.c -o auto_mount;

在sudo chmod +x auto_mount增加可执行权限后,可以如下方法运行:

./auto_mount /dev/sda1 /mnt/sda1; //将/dev/sda1这个设备mount到/mnt/sda1这个目录;
————————————————
版权声明:本文为CSDN博主「背姑娘的锅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zyj_zhouyongjun183/article/details/78116525

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值