libmagic文件类型识别库源码分析

libmagic文件类型识别库的使用》介绍了libmagic库的使用,今天我们来对libmagic库的源码做一个简单的分析。

ligmagic的主要逻辑:启动时加载magic.mgc数据库的特征规则,然后读取要识别文件类型的文件内容,与magic.mgc的特征进行匹配,如果匹配上了,就表示确定了文件的类型,输出的是文件类型的一串描述信息。

magic.mgc的规则比较复杂,具体规则描述可以看https://linux.die.net/man/5/magic

1、magic_open函数:申请内存,创建magic_set句柄

public struct magic_set *magic_open(int flags)
{
return file_ms_alloc(flags);
}

2、magic_load函数:magic.mgc规则加载到magic_set的mlist结构体指针中

magic_load
  -->file_apprentice
    -->magic_getpath(获取magic.mgc文件路径)
      -->apprentice_1
        -->apprentice_map(读取magic.mgc文件)
          -->check_buffer(校验magic.mgc文件,MAGICNO、文件版本version等,相关信息都放入magic_map中)
        -->add_mlist(将magic_map中的内容复制给magic_set的mlist结构体指针)

magic_map结构体:

struct magic_map {
void *p;  //magic.mgc文件内容起始地址
size_t len;  //magic.mgc文件大小
int type; //读取文件类型MAP_TYPE_MMAP
struct magic *magic[MAGIC_SETS];
uint32_t nmagic[MAGIC_SETS];
};

apprentice_map中支持以两种方式读取magic.mgc,一种是mmap映射,一种是常规的read方式:

map->len = (size_t)st.st_size;//文件大小
#ifdef QUICK //文件映射成内存
    if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
        MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
        file_error(ms, errno, "cannot map `%s'", dbname);
        goto error;
    }
    map->type = MAP_TYPE_MMAP;
#else  //读文件的方式
    if ((map->p = CAST(void *, malloc(map->len))) == NULL) {
        file_oomem(ms, map->len);
        goto error;
    }
    if (read(fd, map->p, map->len) != (ssize_t)map->len) {
        file_badread(ms);
        goto error;
    }
    map->type = MAP_TYPE_MALLOC;

3、magic_file和magic_buffer函数:进行特征匹配,识别文件类型

magic_file和magic_bufffer的区别就是magic_file需要先调用file_or_fd读取一下文件的内容和长度,然后再就都是调用file_buffer函数。

magic_file
  -->file_or_fd(读取文件内容)
    -->file_buffer

magic_buffer
  -->file_buffer
    -->file_ascmagic
    -->file_softmagic(遍历特征链表ms->mlist,与文件内容进行匹配)
      -->match(将文件内容与magic.mgc中的特征进行匹配)
        -->mget
        -->mprint
          -->file_printf
            -->file_vprintf(如果匹配上了,最后在这里给ms->o.buf赋值描述信息)
  -->file_getbuffer(返回文件描述信息ms->o.pbuf和ms->o.buf)

file_softmagic函数:

protected int
file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
uint16_t indir_level, uint16_t *name_count, int mode, int text)
{
struct mlist *ml;
int rv, printed_something = 0, need_separator = 0;
uint16_t nc;
if (name_count == NULL) {
        nc = 0;
        name_count = &nc;
    }
//真正进行文件类型比较的地方,遍历mlist链表
for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
            text, 0, indir_level, name_count,
            &printed_something, &need_separator, NULL)) != 0)
return rv;

return 0;

}

file_vprintf函数:

protected int
file_vprintf(struct magic_set *ms, const char *fmt, va_list ap)
{
int len;
char *buf, *newstr;

if (ms->event_flags & EVENT_HAD_ERR)
return 0;
        len = vasprintf(&buf, fmt, ap);
if (len < 0)
goto out;

if (ms->o.buf != NULL) {
            len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
free(buf);
if (len < 0)
goto out;
free(ms->o.buf);
            buf = newstr;
        }
        ms->o.buf = buf; //格式化之后的buf文件描述信息赋值给ms->o.buf
return 0;
    out:
        file_error(ms, errno, "vasprintf failed");
return -1;
}

libmagic规则的匹配过程在match函数中,match以及mget函数就是按这些特征描述,取文件的内容进行计算,与文件的魔数进行比较。如果匹配上了,就最后通过file_vprintf函数给ms->o.buf赋值描述信息,最后通过file_getbuffer函数,返回文件描述信息ms->o.pbuf和ms->o.buf。

好了,libmagic源码的简单分析就到这了。感兴趣的朋友,可以深究一下magic.mgc的格式以及match函数是如何匹配的,这个是libmagic源码中最核心的地方。

有问题的朋友可以进技术交流群获取(先加我微信,备注加群)。喜欢文章内容的朋友,记得关注公众号并加星标哦~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值