读书频道 > 网站 > 网页设计 > Linux软件管理平台设计与实现
1.3.4 header structure
13-09-13    奋斗的小年轻
收藏    我要投稿   
本书是国内首部关于软件管理平台设计与实现(针对大规模Linux服务器集群)的著作,由淘宝资深软件开发工程师和系统运维工程师撰写,书中凝结了作者在淘宝运维一线积累的宝贵经验。不仅详细讲解了RPM和yum等软件管...立即去当当网订购

从上一节讲到的lead部分的内容可以知道, lead数据块的rpmlead结构体从编程角度来讲,是很方便的。要读取结构体的成员,先获取rpmlead结构体的地址(指针),然后直接调用如下结构体成员获取操作就可以获取到RPM的名字。

pointer->name

然而,我们会发现,name 数组只能容纳 66字节的数据,如果包的名字长度超过66 字节,又该怎样处理呢?

有的读者的第一反应可能是:把name 的长度改成 100或者256。是的,这样修改能处理大部分RPM包(因为现实中很少有人会把自己开发的RPM包名称定义为上百个字符),但是,我们仍然需要考虑以下几个问题:

name长度修改了,重新编译rpm命令的源码生成的rpm命令,会按照新的格式读取RPM文件。这样,新版的rpm命令就不能正确读取老版本的RPM文件了,因为结构体rpmlead的大小已经发生了改变。

老版本的rpm命令不能正确读取新版本的RPM文件。

从编程角度来讲,256字节或者更大的数组空间在存储短名称RPM软件包时会造成空间浪费。

要解决以上3个问题,就需要对RPM数据的存储和读取方式进行调整,其中的一个出发点就是:尽量使可变长度数据不要存储在固定大小的结构体中。简单说,就是只见协议,不见业务。这应该也是大多数优秀软件设计的原则吧,实现协议和业务分开,才能保障在业务增加时,对已有功能代码的修改量减到最小,甚至不修改。

在RPM 文件中,为了解决数据统一读取和存储的问题,引入了header structure这个格式的数据元。所谓某种“数据元”,指的是按照一定顺序组织起来的数据块。通过本节对header structure的介绍,我们将认识一个数据元到底是怎样的。

在一个文件中,可以有一个或者多个 header structure;在RPM类型的文件中,只有两个header structure,一个是 signature 数据块,一个是header 数据块。

每一个header structure 包含以下3部分内容:

header structure的头(header)。用来标识一个header structure 的起始位置、大小,以及它包含的数据条目的个数。

索引(index) 列表。index列表包含了多个index条目,其中每个index条目都是对一块数据的描述。每个index描述它指向的数据是什么样的,存储在哪里。根据index就能获取这个index对应的实际数据了。

存储字段(store)。存储了index描述的数据。

注意之所以在这里要对header structure结构做介绍, 是因为它已经在新版RPM中被使用了,为了保持文章的连续和合理性,我们特意在这里安排一些篇幅来讲述这个结构。

在 RPM 文件中,每个 header structure 都是采用以下3字节的magic number来标识其开始的:

"8E AD E8"

而且在前文中,我们已经介绍过, 每个RPM文件有两个header structure—signature 和 header。打开一个RPM文件进行查看,如图1-4所示。

 

在图1-4中,用方框标注了这两个magic number,它们分别是signature和header这两个header structure的开始标识符。

下面来看一下组成header structure的header、 index和store的细节。

1. header

3字节的magic number是header structure的header的开始:3字节之后,是 1 字节的版本号(为1);然后是4字节的保留字;在保留字之后是4字节的整数, 表示在该header structure 中有多少个索引项,也就是说有多少个index;接下来的4字节的整数标识在该header structure 中有多少字节的数据。这些字段在图1-4中都能够看到。

2. index

每个 index 占据16字节的存储空间,前4字节组成一个整数变量Tag,表明该index指向的数据是什么类型的。关于这段描述,引用原文如下:
The first four bytes contain a tag  a numeric value that identifies what type of data is pointed to by the entry. The tag values change according to the header structure's position in the RPM file.

这个字段很容易让人误以为它是用来标识这个index指向的数据是整型、字符串或者数组类型的,其实不然。这里的type实际上就是我们通常所说的变量名称(TAG ID),也就是运行以下命令的输出中,描述各个字段的TAG对应的整数值。
rpm -qpi test.rpm

部分TAG值的定义列表如下:
#define RPMTAG_NAME                   1000
#define RPMTAG_VERSION                1001
#define RPMTAG_RELEASE                1002
#define RPMTAG_SERIAL                 1003
#define RPMTAG_SUMMARY                1004
#define RPMTAG_DESCRIPTION            1005
#define RPMTAG_BUILDTIME              1006
#define RPMTAG_BUILDHOST              1007
#define RPMTAG_INSTALLTIME            1008
#define RPMTAG_SIZE                   1009

接下来的4字节整数(4~7)才是前4字节代表的变量的类型,即整数、字符串等。具体定义在文件 /usr/include/rpm/header.h中。
typedef enum rpmTagType_e {
    #define RPM_MIN_TYPE            0
        RPM_NULL_TYPE               =  0,
        RPM_CHAR_TYPE               =  1,
        RPM_INT8_TYPE               =  2,
        RPM_INT16_TYPE              =  3,
        RPM_INT32_TYPE              =  4,
        RPM_STRING_TYPE             =  6,
        RPM_BIN_TYPE                =  7,
        RPM_STRING_ARRAY_TYPE       =  8,
        RPM_I18NSTRING_TYPE         =  9
    #define RPM_MAX_TYPE            9
    } rpmTagType;

其中,STRNG_TYPE 是以空字符结束的字符串;STRING_ARRAY_TYPE是由多个 STRING_TYPE变量组成的字符串数组。

接下来的 8 ~11这4字节的整数,是该index 对应的数据存储在store段的偏移量。

最后12~15这4字节的整数,表明了该index指向的数据有多少个元素,主要用于STRING 和 STRING_ARRAY类型变量:对于STRING变量,取值是1;对于STRING_ARRAY变量,取值是STRING的个数。

3. store

store是header structure 中标注的数据实际存储的地方,关于这个元素,在分析时有以下几点要注意:

每个 STRING 类型变量都是以空字符结尾的。

对于以整数类型存储的变量,都是按照它的自然边界对齐存储的,也就是说,16位整数用2字节存储,32位整数用4字节存储,64位整数用8字节存储,以此类推。

所有数据都是以网络字节序存储的。

注意在上一小节分析index的时候,store的内容就被分析出来了,为避免重复,本小节未给出具体的分析。index类似于指针,而store则是指针指向的值。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:1.3 功能
下一篇:1.5 小结
相关文章
图文推荐
JavaScript网页动画设
1.9 响应式
1.8 登陆页式
1.7 主题式
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站