Linux C与C++一线开发实践之二 Linux文件系统
Posted 夜色魅影
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux C与C++一线开发实践之二 Linux文件系统相关的知识,希望对你有一定的参考价值。
文件系统是操作系统中负责管理和存储文件的软件系统。
当我们在Linux下查看根目录下的内容时,见到很多的目录文件,那么这些都是一些什么文件呢?下面我们来先了解下:
目录名 | 存放的内容 |
---|---|
/ | 根目录 |
/bin | 必备的用户命令程序,例如ls、cp等 |
/boot | Linux启动时用到的一些文件,如/boot/vmlinuz为Linux内核文件 |
/sbin | 必备的系统管理员命令,如:ifconfig、reboot等 |
/dev | 设备文件,如mtdblock0、tty1等 |
/etc | 系统配置文件 |
/lib | 必要的链接库,如C链接库、内核模块 |
/home | 普通用户主目录 |
/root | root用户主目录 |
/usr/bin | 非必备的用户程序,如find、du等 |
/usr/sbin | 非必备的管理员命令,如chroot、inetd等 |
/var | 系统运行过程中经常变化的文件,如日志文件,登入文件等 |
/proc | 此目录不占磁盘空间,数据都在内存中,如系统核心、外部设备、网络状态等,比较重要的目录有/proc/cpuinfo、/proc/interrupts、/proc/dma、/proc/ioports、/proc/net/*等 |
/tmp | 程序执行过程产生的临时文件 |
/srv | 服务程序启动后需要访问的数据目录,如www服务需要访问的网页数据就存放在/srv/www内 |
/usr | 应用程序存放目录,如:程序安装文件,共享数据,库文件,程序说明文件等 |
文件系统
Linux文件在底层结构上其实类似我们的书本,包括目录和内容。Linux上查找文件也类似,所有文件都有个索引节点,然后根据索引信息来定位内容地址。这是个树形结构保存。索引节点在这个树形结构中是用一个整型数据表示的,所以文件名字需要有个对应的映射表,这个映射表我们称为目录项。
通俗讲一个Linux上文件在磁盘中存储包括:索引节点、目录项、数据这三块组成的。
我们平时点击打开一个文件,实际上系统内部是分三个步骤:
(1)系统通过目录项找到这个文件名对应的索引节点号。
(2)通过索引节点号获取节点信息。
(3)根据索引节点信息找到文件数据所在的“块”,读出数据。
接下来我们来看看文件的属性信息(ls -l查看):
d | rwx | r-x | r-x | 19 | root | root | 4096 | 1月 21 2019 | var |
---|---|---|---|---|---|---|---|---|---|
文件类型 | 文件所有者权限(读r、写w、可执行x) | 文件所属用户组权限(-没有对应权限) | 其它用户权限 | 链接数 | 所属用户 | 所属用户组 | 文件大小 | 文件最后修改日期 | 文件名 |
文件类型:
- -:普通文件
- d:目录
- b:块设备文件(硬盘、光驱等)
- c:字符设备文件(“猫”等串口设备)
- l:链接文件(硬链接、软链接)
- p:管道文件
- s:套接口文件/数据接口文件(如:启动一个mysql服务器产生的mysql.sock文件)
注释:
1.硬链接其实就是给现有文件起的别名,类似于书本两个目录都指向相同的内容。而软链接本身它是一个特殊的文件,这个文件中包含的是另一个源文件的位置信息内容,因此,通过访问这个“快捷方式"就可以迅速定位到软链接所指向的源文件。链接文件其实就是扩展了我们现有文件查找的索引方式。
2.硬链接就是创建目录项,通过link/unlink两个函数创建和删除。
I/O操作
常规讲就是对文件的读写操作,相信我们对c库的文件I/O函数比较熟悉,比如fopen、fread/fwrite、fclose、fseek等。其实I/O操作基本就是这些东西。今天我们来总结下,Linux下对文件操作总共有3种方式,至于以后你们要用哪一种读写文件看自己喜好:
(1)C库文件操作
(2)C++文件流(open、close、>>、<<、seekp/seekg、write、read等)
(3)Linux系统调用(open、creat、close、read、write、lseek等)
关于文件的一些其它操作
1.stat()函数,获取文件的状态信息。
2.fcntl()函数,文件锁定。包括建议锁和强制锁,它们代码一致,只需要修改系统配置就可以切换两种锁。
3.mmap()函数,建立文件和内存映射。在要求高性能的应用中比较常用。
等
对文件操作的接口就不详细介绍了,都差不多,就是些接口的调用,我们主要看看它运用的场景,如在保存本地配置,导出配置文件的自动化工具,项目加密解密等。
文件操作实战
实战的示例:我们有一个加了密的游戏资源文件,目标是要把这个资源文件破解出来,一张张原图还原。
下面这个是网络上找的一个加了密的游戏资源文件:
首先我们看看这个文件大小有47M多,可以猜测到它是将很多的散图文件集中写到这一个文件里了。那我们怎么还原它的散图呢?
我们先自己思考下,把多个文件写入一个文件中,要能够还原,那肯定得记录每个文件在这个总文件中的位置信息。类似我们网络传输数据处理沾包丢包问题一样,每个消息包加包头和数据组成。这个包头就记录了消息长度等信息,以此来做检验。
根据分析这个资源包肯定要记录每个文件位置,名字,大小等信息,即索引。那我们沿着这个思路,就是先要想办法找到这个所谓“索引”信息,然后根据这个索引信息还原数据。
下面推荐一个文件二进制查看工具:FlexHEX,我们把images.pak源文件用这个工具打开,如下:
我尝试搜索了下游戏资源常用格式.PNG和.jpg,发现png=186,jpg=22,加起来=208。所以我大胆猜测这个208应该就近视是散图文件数量了。而我又观察查看器,发现在文件开始的第二个4字节刚好等于208。
由此我几乎可以断定这个文件的索引信息就是写在文件开始位置。以此,我把这个文件前面一段数据以4字节为单元,全部读出来。很容易分析出这个包结构如下:
索引文件大小 | 图片真实数量 | 每张图片的偏移、大小、名字(208个) |
---|
注:在读取图片名字时遇到一个坑,后面断点看数据发现它的名字是用的Unicode编码,一个字符占2字节,所以我们用char[]读取时要注意转化下。
结构明确了,下面就是按照这个结构码代码了:
#include "stdafx.h"
struct FileUnit
int offset; //文件偏移
int fileSize; //文件大小
int fileNameLength; //文件名长度
char fileName[999]; //文件名
;
int _tmain(int argc, _TCHAR* argv[])
//散图信息
FileUnit m_FT[300];
memset(m_FT, 0, sizeof(m_FT));
FILE *pf = fopen("images.pak","rb");
int indexSize; //索引大小
fread(&indexSize, sizeof(int), 1, pf);
int imageNum; //图片总数
fread(&imageNum, sizeof(int), 1, pf);
//读取每张图片信息
for(int i = 0; i < imageNum; i++)
fread(&m_FT[i].offset, sizeof(int), 1, pf); //偏移
fread(&m_FT[i].fileSize, sizeof(int), 1, pf); //图片大小
fread(&m_FT[i].fileNameLength, sizeof(int), 1, pf); //图片名字长度
//图片名字是Unicode码储存,转char[]
char tempName[999] = ;
fread(tempName, sizeof(char), m_FT[i].fileNameLength, pf);
bool isIn = false;
int tempIndex = 0;
for(int m = 0; m < m_FT[i].fileNameLength; m += 2)
if (isIn)
m_FT[i].fileName[tempIndex++] = tempName[m];
// 92(\\\\去掉目录名字)
if(tempName[m] == 92)
isIn = true;
//还原散图资源
for(int i = 0; i < imageNum; i++)
FILE *pDestFile = fopen(m_FT[i].fileName, "wb");
fseek(pf, indexSize + m_FT[i].offset + 4, SEEK_SET);
for(int m = 0; m < m_FT[i].fileSize; m++)
fputc(fgetc(pf), pDestFile);
fclose(pDestFile);
fclose(pf);
return 0;
运行后,如愿解出资源:
以上是关于Linux C与C++一线开发实践之二 Linux文件系统的主要内容,如果未能解决你的问题,请参考以下文章
Linux C与C++一线开发实践之四 Linux进程间的通信