Linux C与C++一线开发实践之二 Linux文件系统

Posted 夜色魅影

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux C与C++一线开发实践之二 Linux文件系统相关的知识,希望对你有一定的参考价值。

文件系统是操作系统中负责管理和存储文件的软件系统。

当我们在Linux下查看根目录下的内容时,见到很多的目录文件,那么这些都是一些什么文件呢?下面我们来先了解下:

目录名存放的内容
/根目录
/bin必备的用户命令程序,例如ls、cp等
/bootLinux启动时用到的一些文件,如/boot/vmlinuz为Linux内核文件
/sbin必备的系统管理员命令,如:ifconfig、reboot等
/dev设备文件,如mtdblock0、tty1等
/etc系统配置文件
/lib必要的链接库,如C链接库、内核模块
/home普通用户主目录
/rootroot用户主目录
/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查看):

drwxr-xr-x19rootroot40961月 21 2019var
文件类型文件所有者权限(读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进程间的通信

Linux C与C++一线开发实践之四 Linux进程间的通信

Linux C与C++一线开发实践之三 Linux多进程

Linux C与C++一线开发实践之三 Linux多进程

Linux C与C++一线开发实践之六 多线程高级编程

Linux C与C++一线开发实践之六 多线程高级编程