总体情况

首先我们先要有一个makeisofs这样的制作iso文件的工具,用它来制作一个iso文件,里面放上几个非空文件(至于为什么非空,最后会有介绍)

然后再有一个hexdump这样二进制文件查看器

先来看一下这个表格

ISO 9660 File System
System Area (32,768 B) Unused by ISO 9660
Data Area
Volume Descriptor (2,048 B)
Volume Descriptor (2,048 B)
...
Volume Descriptor Set Terminator (2,048 B)
Optional space
Root directory
Directories and files

先看第一行,说的是前32768个字节被保留,十进制不好表示,换成十六进制就是0x8000

照此我们先用hexdump看一下我的mkisofs生成的iso文件

hexdump -C os.iso | less

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00008000  01 43 44 30 30 31 01 00  4c 49 4e 55 58 20 20 20  |.CD001..LINUX   |
00008010  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00008020  20 20 20 20 20 20 20 20  43 44 52 4f 4d 20 20 20  |        CDROM   |
00008030  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00008040  20 20 20 20 20 20 20 20  00 00 00 00 00 00 00 00  |        ........|

正好符合,前0x8000字节都是0,不过貌似这是未使用而不是保留,所以如果你的工具往里面写点什么也应该可以

向下看是Data Area,先看第一个部分Volume Descriptor

Volume Descriptor

Volume Descriptor ← 2,048 bytes →
Parts Type Identifier (always 'CD001') Version (always 0x01) Data (depends on type), can be subdivided into several fields
Sizes 1 byte 5 bytes 1 byte 2,041 bytes

这是一个Volume Descriptor的基本模板

第一个字节是Type,来看一下取值范围

Value Description
0 Boot Record
1 Primary Volume Descriptor
2 Supplementary Volume Descriptor
3 Volume Partition Descriptor
4-254 Reserved
255 Volume Descriptor Set Terminator

255(0xff)表示这是最后一个Volume Descriptor,4-254都是保留,剩下的我们只打算看Primary Volume Descriptor,其他的都无视掉

接下来是Identifier,五个字节,总是"CD001",我们写程序读取的时候就可以判断,不是就说明出错了

然后版本,一个字节,无视掉

剩下的就是最重要的数据区了,对于不同的Type有不同的数据,Volume Descriptor Set Terminator只是一个标记,它没有数据

所以我们就很清楚了,我们只用看一下Primary Volume Descriptor的数据区就好了

Primary Volume Descriptor

这个表格非常长,很多我们都用不到,我们只用到一个信息,我们也只贴出这一个

Offset Length (bytes) Field name Datatype Description
156 34 Directory entry for the root directory - Note that this is not an LBA address, it is the actual Directory Record, which contains a zero-length Directory Identifier, hence the fixed 34 byte size.

偏移是156,长度是34(0x22),根目录的入口,这是一个什么格式呢?这就是我们今天新出现的最后一个,也是最重要的一个格式

Directories

Offset Size Description
0 1 Length of Directory Record.
1 1 Extended Attribute Record length.
2 8 Location of extent (LBA) in both-endian format.
10 8 Data length (size of extent) in both-endian format.
18 7 Recording date and time (see format below).
25 1 File flags (see below).
26 1 File unit size for files recorded in interleaved mode, zero otherwise.
27 1 Interleave gap size for files recorded in interleaved mode, zero otherwise.
28 4 Volume sequence number - the volume that this extent is recorded on, in 16 bit both-endian format.
32 1 Length of file identifier (file name). This terminates with a ';' character followed by the file ID number in ASCII coded decimal ('1').
33 (variable) File identifier.
(variable) 1 Padding field - zero if length of file identifier is odd, otherwise, this field is not present. This means that a directory entry will always start on an even byte number.
(variable) (variable)

System Use - The remaining bytes up to the maximum record size of 255 may be used for extensions of ISO 9660. The most common one is the System Use Share Protocol (SUSP) and its application, the Rock Ridge Interchange Protocol (RRIP).

这个结构既可以代表目录,也可以代表文件

鉴于我们现在的这个结构来自Volume Descriptor中的,它代表ROOT目录,所以我们就不用判断Flags而直接认定就是文件加了

看一下hexdump的输出:

00008090  00 00 00 00 00 00 00 16  00 00 00 00 22 00 18 00  |............"...|
000080a0  00 00 00 00 00 18 00 08  00 00 00 00 08 00 71 0c  |..............q.|
000080b0  09 01 04 2f 20 02 00 00  01 00 00 01 01 00 20 20  |.../ .........  |

开始地址是第一行的22那个地方,表明有0x22个字节,正好34个,与我们之前的描述相符

看一下"File identifier",就是这个文件的名称,这里是"/",前一个字节表示长度

然后再看一下"Location of extent (LBA) in both-endian format",有8个字节,前四个字节是小端的LBA号,后四个字节是大端的LBA号

因为我们后面要用C语言读取,所以当然考虑小端而不是大端,尽管大端更符合人类思维.....

这里是18 00 00 00 00 00 00 18,表明LBA号是18

对于目录,这里指向的LBA里储存的数据是一个这个结构的数组,对于文件,当然储存的是文件内容了
计算一下偏移 24 * 2048 = 0x18 * 0x800 = 0xc000

再看一下:

0000c000  90 00 18 00 00 00 00 00  00 18 00 08 00 00 00 00  |................|
0000c010  08 00 71 0c 09 01 04 2f  20 02 00 00 01 00 00 01  |..q..../ .......|
0000c020  01 00 53 50 07 01 be ef  00 52 52 05 01 81 50 58  |..SP.....RR...PX|
0000c030  2c 01 ed 41 00 00 00 00  41 ed 02 00 00 00 00 00  |,..A....A.......|
0000c040  00 02 e8 03 00 00 00 00  03 e8 e8 03 00 00 00 00  |................|
0000c050  03 e8 18 00 00 00 00 00  00 18 54 46 1a 01 0e 71  |..........TF...q|
0000c060  0c 09 01 04 2f 20 71 0a  06 03 39 2e 20 71 0c 09  |..../ q...9. q..|
0000c070  01 04 2f 20 43 45 1c 01  19 00 00 00 00 00 00 19  |../ CE..........|

第一个的大小是0x90,它的LBA指向是0x18,我没有仔细研究过这种指向的LBA反而小于等于自身LBA的这种结构

猜测可能是类似"/""."".."之类的"目录",由于我们并不需要把这些打印出来,而且打印如果不加判断可能会无限递归,我们先将其略过

说了这是一个数组,所以直接找到偏移0x90 + 0x00处的地方,发现指向的LBA仍然是0x18,继续略过,几次之后找到了一个文件

0000c0f0  0a 06 03 39 2e 20 71 0c  09 01 04 2f 20 00 84 00  |...9. q..../ ...|
0000c100  1b 00 00 00 00 00 00 1b  00 02 00 00 00 00 02 00  |................|
0000c110  71 0c 09 01 04 2e 20 00  00 00 01 00 00 01 0a 42  |q..... ........B|
0000c120  4f 4f 54 2e 42 49 4e 3b  31 00 52 52 05 01 89 4e  |OOT.BIN;1.RR...N|

起始地址是第一行的84那里,然后往下找,找到"1b 00 00 00 00 00 00 1b",这就是刚刚的"回文"LBA号

由于这是一个文件,说明这个文件内容的LBA号就是0x1b

"00 02 00 00 00 00 02 00"是"回文"的大小,表明这个文件大小是0x200,就是512个字节

然后第三行倒数第二个字节,0a表示的是这个文件名的长度

往后的0a个字节都是这个文件名 "BOOT.BIN;1"

(ISO储存文件会自动把文件后面加上;1,并且小写转换成大写,这部分我们要自己处理,文件夹不会加上;1)

遍历所有文件并打印

接下来我们就要把以上讨论的问题转化为代码了,先来看第一部分,寻找Primary Volume Descriptor

  1. static int parseISO9660FileSystem(IDEDevice *device)

  2. {

  3. /*See also http://wiki.osdev.org/ISO_9660.*/

  4. /*And http://en.wikipedia.org/wiki/ISO_9660.*/

  5. u8 *buf8 = (u8 *)ideIOBuffer;

  6. /*System Area (32,768 B) Unused by ISO 9660*/

  7. /*32786 = 0x8000.*/

  8. u64 lba = (0x8000 / 0x800); /*从0x8000的地方开始寻找.*/

  9. for(;;++lba)

  10. {

  11. if(ideRead(device,lba,ATAPI_SECTOR_SIZE,buf8))

  12. return -1; /*It may not be inserted if error.*/

  13. /*Identifier is always "CD001".*/

  14. if(buf8[1] != 'C' ||

  15. buf8[2] != 'D' ||

  16. buf8[3] != '0' ||

  17. buf8[4] != '0' ||

  18. buf8[5] != '1' ) /*判断CD001 不符合直接返回.*/

  19. return -1;

  20. if(buf8[0] == 0xff) /*Volume Descriptor Set Terminator.*/

  21. return -1; /*如果这是最后一个 也返回.*/

  22. if(buf8[0] != 0x01 /*Primary Volume Descriptor.*/)

  23. continue; /*不是Primary Volume Descriptor就继续*/

  24. /*Directory entry for the root directory.*/

  25. if(buf8[156] != 0x22 /*Msut 34.*/)

  26. return -1; /*看前边,这里必须是34个字节.*/

  27. /*Location of extent (LBA) in both-endian format.*/

  28. lba = *(u32 *)(buf8 + 156 + 2);

  29. break; /*读LBA,跳出.*/

  30. }

  31. return parseISO9660FileSystemDir(device,lba,buf8,0); /*分析ROOT目录里的文件.*/

  32. }

再来看一下parseISO9660FileSystemDir,这是一个简单的递归函数

  1. static int parseISO9660FileSystemDir(

  2. IDEDevice *device,u64 lba,u8 *buf8,int depth)

  3. {

  4. u64 offset = 0; /*要读的文件(夹)的信息结构的偏移.*/

  5. u8 isDir = 0; /*是否是文件夹.*/

  6. u8 needRead = 0; /*需不需要重新读.*/

  7. if(ideRead(device,lba,ATAPI_SECTOR_SIZE,buf8))

  8. return -1; /*读取失败直接返回.*/

  9. for(;;offset += buf8[offset + 0x0] /*Length of Directory Record.*/)

  10. {

  11. while(offset >= ATAPI_SECTOR_SIZE)

  12. {

  13. offset -= ATAPI_SECTOR_SIZE;

  14. ++lba;

  15. needRead = 1;

  16. /*Read again.*/

  17. } /*偏移超出这个扇区的范围就修正一下.*/

  18. if(needRead)

  19. if(ideRead(device,lba,ATAPI_SECTOR_SIZE,buf8))

  20. return -1; /*如果修正了就再读一次.*/

  21. needRead = 0;

  22. if(buf8[offset + 0x0] == 0x0) /*No more.*/

  23. break; /*大小是0说明结束了,退出.*/

  24. /*Location of extent (LBA) in both-endian format.*/

  25. u64 fileLBA = *(u32 *)(buf8 + offset + 0x2);

  26. if(fileLBA <= lba)

  27. continue; /*获取文件LBA,小于就继续吧.*/

  28. int __depth = depth;

  29. while(__depth--)

  30. printk("--"); /*形成一个视觉效果.*/

  31. isDir = buf8[offset + 25] & 0x2; /*Is it a dir?*/

  32. u64 filesize = *(u32 *)(buf8 + offset + 10);

  33. /*Length of file identifier (file name).

  34. * This terminates with a ';' character

  35. * followed by the file ID number in ASCII coded decimal ('1').*/

  36. u64 filenameLength = buf8[offset + 32];

  37. if(!isDir) /*如果是文件就要删掉最后的";1".*/

  38. filenameLength -= 2; /*Remove ';' and '1'.*/

  39. char filename[filenameLength + 1]; /*Add 1 for '\0'.*/

  40. memcpy((void *)filename,

  41. (const void *)(buf8 + offset + 33),

  42. filenameLength); /*把文件名复制过来.*/

  43. if((!isDir) && (filename[0] == '_'))

  44. filename[0] = '.';

  45. if((!isDir) && (filename[filenameLength - 1] == '.'))

  46. filename[filenameLength - 1] = '\0';

  47. else

  48. filename[filenameLength] = '\0'; /*做一些修正.*/

  49. /*To lower.*/

  50. for(u64 i = 0;i < filenameLength;++i)

  51. if((filename[i] <= 'Z') && (filename[i] >= 'A'))

  52. filename[i] -= 'A' - 'a'; /*全部转换成小写(好看一点).*/

  53. if(isDir)

  54. {

  55. printk("LBA:%d.",(int)fileLBA);

  56. printk("Dirname:%s\n",filename); /*打印出目录信息.*/

  57. parseISO9660FileSystemDir(device,fileLBA,buf8,depth + 1); /*递归.*/

  58. ideRead(device,lba,ATAPI_SECTOR_SIZE,buf8); /*上一个递归修改了buf8,重新读.*/

  59. /*We must read again.*/

  60. }

  61. else

  62. {

  63. if(filesize != 0)

  64. printk("LBA:%d.",(int)fileLBA);

  65. else

  66. printk("Null file,no LBA."); /*如果这个文件是空的,LBA地址无效.*/

  67. /*这也就是刚开始时为什么要用非空文件的原因,空文件看不到正确的LBA地址.*/

  68. /*LBA may not be right if this file is null!*/

  69. printk("Filename:%s\n",filename);

  70. }

  71. }

  72. return 0; /*返回......*/

  73. }

参考资料

ISO9660 维基百科:http://en.wikipedia.org/wiki/ISO_9660

ISO9660 OSDEV百科:http://wiki.osdev.org/ISO_9660

转自 https://blog.csdn.net/goodqt/article/details/17202109

ISO9660文件系统分析相关推荐

  1. 光盘隐藏文件夹 linux,linux常用命令大全2--挂载/dpkg/文件系统分析/apt/光盘/关机...

    挂载一个文件系统 mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘 - 确定目录 '/ mnt/hda2' 已经存在 umount /dev/hda2 卸载一个叫做hda2 ...

  2. 京东 ChubaoFS 分布式文件系统分析

    ChubaoFS(CFS)是京东开发的一分布式文件系统和对象存储系统.其主要声称是云原生的分布式文件系统,主要用于k8s容器环境. CFS是一个分布式的文件系统,支持多元数据服务器,支持posix接口 ...

  3. linux ext4文件系统分析,LinuxEXT4文件系统分析

    ISSN1009-3044 第7卷第年5月)14期(2011电脑知识与技术ComputerKnowledgeandTechnology Vol.7,No.14,May2011,pp.3443-3446 ...

  4. Linux内核与文件系统分析

    1.Linux内核源代码目录结构 arch:包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如i386.arm.powerpc.mips等. block:块设备驱动程序I/O调度. crypt ...

  5. 无法扩展该卷 因为群集的数量将超过文件系统_Ubifs文件系统分析

    转载是一种动力 分享是一种美德 1.  引言 UBIFS,Unsorted Block Image File System,无排序区块图像文件系统.它是用于固态硬盘存储设备上,并与LogFS相互竞争, ...

  6. SDU信息门户(8)组队和文件系统分析

    2021SC@SDUSC 目录 一.概述 1.需求背景: 2.需求描述 : 二.代码分析 1.参数指定 2.导包并确定常量 3.获得数据库并进行相关操作 4.关键信息获取 5.建立线程池 三.总结 一 ...

  7. linux设备模型:devtmpfs虚拟文件系统分析

    devtmpfs是一个设备文件系统,它将其所有文件保存在虚拟内存中. devtmpfs中的所有内容都是临时的,因为不会在您的硬盘驱动器上创建任何文件.如果卸载devtmpfs实例,其中存储的所有内容都 ...

  8. exfat文件系统分析

    本文详细分析了exfat文件系统结构,并通过实际数据对exfat文件系统各个字段中的定义进行解释. 目录 1文件系统整体布局 2 -1Master Boot Record(MBR)-MBR分区 2.1 ...

  9. linux fat get entry,Linux kernel FAT32文件系统分析

    文本探讨了Linux kernel中对fat32文件系统的实现,关于fat文件的格式可以查看微软的fat白皮书. 1.     FAT表操作 FAT文件系统中,使用FAT表标记哪个cluster被占用 ...

  10. Android文件系统分析

    感谢conowen大神 原文地址:http://blog.csdn.net/conowen/article/details/7251057 1.Android文件系统的结构 官方Android源码编译 ...

最新文章

  1. 开机秒全国99%电脑 实战UEFI安装Win8
  2. How to use USB to do charger detection instead of PMIC?
  3. [MIPS汇编语言]对于数的输入和输出
  4. 计算机英语笑话,关于计算机的幽默笑话
  5. linux系统访问文件夹ls,Linux系统目录结构,文件类型以及ls、alias命令
  6. java内容寻址_java – 获取方法对象而不按名称寻址方法
  7. 终于读完Code complete 2nd edtion
  8. 使用spring框架时,使用xml还是注解
  9. 教你几招——交换变量数值
  10. HTML5缓存之 WebStorage
  11. 深度装机大师一键重装_“云骑士一键重装系统”,看标题就知道装系统原来如此简单...
  12. Typora恢复忘记保存的文件
  13. 安全报告处理 HCL AppScan Standard
  14. java 异步网络编程_java网络编程实战 - 基于BIO的伪异步、高并发、全双工、长链接持续消息IO的网络编程...
  15. 【智能制造】“OEE智能盒子”-智能制造时代企业制造能力的评测与改进工具
  16. 苹果大战泄密者内幕曝光:从中国工厂到美国总部
  17. Ubuntu 上安装 Freemind 并支持中文
  18. python下载谷歌地图瓦片_python抓取天地图瓦片
  19. werkzeug routing RequestRedirect 308 Permanent Redirect None
  20. 说说 Google AdSense、百度联盟和搜狗联盟

热门文章

  1. PageOffice在线预览word/excel/ppt/pdf
  2. 中国象棋游戏设计与实现
  3. matlab2012a for mac,matlab 2016a mac |matlab 2016a for mac免费版专业版 32位/64位 - 系统天堂...
  4. Windows系统一台主机供多人同时使用的讨论与软件
  5. 一个完整的、全面k8s化的集群稳定架构(值得借鉴)
  6. JAVA——电子商城三级分类目录查询-递归树形数据结构
  7. springboot开发微信公众号(一)创建、查询、删除菜单(附源码)
  8. 类模板和模板类的关系
  9. Vue 项目断网时跳转到网络错误页面
  10. Java基础-SSM之Spring的AOP编程