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这个工具,分别读取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 |[email protected]|
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 |................|
根据上面的实验结果,所实现的获取分区文件系统函数如下:
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
#include
#include
#include
#include
/**
* [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这个目录;