之前v1.1.0的版本已经可以通过ATAPI驱动来读取光盘里的二进制数据,现在只需要对这些数据加以解析,就可以访问到光盘里所需的文件和目录了。 光盘所使用的标准文件系统是ISO 9660,至少GRUB所生成的zenglOX.iso使用的就是这种标准的文件系统格式,我们只要掌握了ISO 9660的结构,就可以从光盘中读取出所需的文件了...
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 卷集结束 |
Offset | Length (bytes) | Field name | Datatype | Description |
---|---|---|---|---|
0 | 1 |
Type Code 类型代码 |
int8 8位的字节值 |
Always 0x01 for a Primary Volume Descriptor. 主卷描述符类型代码始终是0x01 |
1 | 5 |
Standard Identifier 标识符 |
strA A类型的字符串 |
Always 'CD001'. 标识符始终是 'CD001' |
6 | 1 |
Version 版本号 |
int8 8位的字节值 |
Always 0x01. 版本号始终是 0x01 |
7 | 1 | Unused | - | Always 0x00. |
8 | 32 | System Identifier | strA | The name of the system that can act upon sectors 0x00-0x0F for the volume. |
40 | 32 | Volume Identifier | strD | Identification of this volume. |
72 | 8 | Unused Field | - | All zeroes. |
80 | 8 | Volume Space Size | int32_LSB-MSB | Number of Logical Blocks in which the volume is recorded. |
88 | 32 | Unused Field | - | All zeroes. |
120 | 4 | Volume Set Size | int16_LSB-MSB | The size of the set in this logical volume (number of disks). |
124 | 4 | Volume Sequence Number | int16_LSB-MSB | The number of this disk in the Volume Set. |
128 | 4 | Logical Block Size | int16_LSB-MSB | The size in bytes of a logical block. NB: This means that a logical block on a CD could be something other than 2 KiB! |
132 | 8 |
Path Table Size 路径表大小 |
int32_LSB-MSB 先是小字节序的32位 整数值, 然后再跟随一个 大字节序的 32位整数值 |
The size in bytes of the path table. 路径表的以字节为单位的尺寸大小 |
140 | 4 |
Location of Type-L Path Table 小字节序的路径表的LBA位置 |
int32_LSB 小字节序的32位 整数值 |
LBA location of the path table. The path table pointed to contains only little-endian values. 路径表的LBA位置,该路径表里的所有字段的值都是小字节序的 |
144 | 4 | Location of the Optional Type-L Path Table | int32_LSB | LBA location of the optional path table. The path table pointed to contains only little-endian values. Zero means that no optional path table exists. |
148 | 4 | Location of Type-M Path Table | int32_MSB | LBA location of the path table. The path table pointed to contains only big-endian values. |
152 | 4 | Location of Optional Type-M Path Table | int32_MSB | LBA location of the optional path table. The path table pointed to contains only big-endian values. Zero means that no optional path table exists. |
156 | 34 |
Directory record for the root directory Root根目录的目录记录 |
- Directory record 有自己独立的结构 |
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. 这是一个独立的完整的Directory record(目录记录),由于该目录记录里的目录名有固定的长度,所以尺寸就是固定的值34 |
190 | 128 | Volume Set Identifier | strD | Identifier of the volume set of which this volume is a member. |
318 | 128 | Publisher Identifier | strA | The volume publisher. For extended publisher information, the first byte should be 0x5F, followed by the filename of a file in the root directory. If not specified, all bytes should be 0x20. |
446 | 128 | Data Preparer Identifier | strA | The identifier of the person(s) who prepared the data for this volume. For extended preparation information, the first byte should be 0x5F, followed by the filename of a file in the root directory. If not specified, all bytes should be 0x20. |
574 | 128 | Application Identifier | strA | Identifies how the data are recorded on this volume. For extended information, the first byte should be 0x5F, followed by the filename of a file in the root directory. If not specified, all bytes should be 0x20. |
702 | 38 | Copyright File Identifier | strD | Filename of a file in the root directory that contains copyright information for this volume set. If not specified, all bytes should be 0x20. |
740 | 36 | Abstract File Identifier | strD | Filename of a file in the root directory that contains abstract information for this volume set. If not specified, all bytes should be 0x20. |
776 | 37 | Bibliographic File Identifier | strD | Filename of a file in the root directory that contains bibliographic information for this volume set. If not specified, all bytes should be 0x20. |
813 | 17 | Volume Creation Date and Time | dec-datetime | The date and time of when the volume was created. |
830 | 17 | Volume Modification Date and Time | dec-datetime | The date and time of when the volume was modified. |
847 | 17 | Volume Expiration Date and Time | dec-datetime | The date and time after which this volume is considered to be obsolete. If not specified, then the volume is never considered to be obsolete. |
864 | 17 | Volume Effective Date and Time | dec-datetime | The date and time after which the volume may be used. If not specified, the volume may be used immediately. |
881 | 1 | File Structure Version | int8 | The directory records and path table version (always 0x01). |
882 | 1 | Unused | - | Always 0x00. |
883 | 512 | Application Used | - | Contents not defined by ISO 9660. |
1395 | 653 | Reserved | - | Reserved by ISO. |
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 even, 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). |
Offset | Size | Description |
---|---|---|
0 | 1 | Number of years since 1900. |
1 | 1 | Month of the year from 1 to 12. |
2 | 1 | Day of the month from 1 to 31. |
3 | 1 | Hour of the day from 0 to 23. |
4 | 1 | Minute of the hour from 0 to 59. |
5 | 1 | Second of the minute from 0 to 59. |
6 | 1 | Offset from GMT in 15 minute intervals from -48 (West) to +52 (East). |
Bit | Description |
---|---|
0 | If set, the existence of this file need not be made known to the user (basically a 'hidden' flag. |
1 | If set, this record describes a directory (in other words, it is a subdirectory extent). |
2 | If set, this file is an "Associated File". |
3 | If set, the extended attribute record contains information about the format of this file. |
4 | If set, owner and group permissions are set in the extended attribute record. |
5 & 6 | Reserved |
7 | If set, this is not the final directory record for this file (for files spanning several extents, for example files over 4GiB long. |
Offset | Size | Description |
---|---|---|
0 | 1 | Length of Directory Identifier |
1 | 1 | Extended Attribute Record Length |
2 | 4 | Location of Extent (LBA). This is in a different format depending on whether this is the L-Table or M-Table (see explanation above). |
6 | 2 | Directory number of parent directory (an index in to the path table). This is the field that limits the table to 65536 records. |
8 | (variable) | Directory Identifier (name) in d-characters. |
(variable) | 1 | Padding Field - contains a zero if the Length of Directory Identifier field is odd, not present otherwise. This means that each table entry will always start on an even byte number. |
/* zlox_iso.h -- 包含和iso 9660文件系统相关的结构定义 */ #ifndef _ZLOX_ISO_H_ #define _ZLOX_ISO_H_ #include "zlox_common.h" #include "zlox_fs.h" #define ZLOX_PVD_START_LBA 16 #define ZLOX_PVD_TYPE 1 #define ZLOX_VD_TERMINATOR 255 #define ZLOX_VD_ID_1 0x43 // 'C' #define ZLOX_VD_ID_2 0x44 // 'D' #define ZLOX_VD_ID_3 0x30 // '0' #define ZLOX_VD_ID_4 0x30 // '0' #define ZLOX_VD_ID_5 0x31 // '1' #define ZLOX_PVD_PTSZ_OFFSET 132 #define ZLOX_PVD_LPT_OFFSET 140 #define ZLOX_PVD_ROOT_OFFSET 156 struct _ZLOX_PATH_TABLE_ENTRY { ZLOX_UINT8 dir_id_length; ZLOX_UINT8 ext_length; ZLOX_UINT32 lba; ZLOX_UINT16 parent_index; }__attribute__((packed)); typedef struct _ZLOX_PATH_TABLE_ENTRY ZLOX_PATH_TABLE_ENTRY; struct _ZLOX_ISO_DIR_RECORD { ZLOX_UINT8 length; ZLOX_UINT8 ext_length; ZLOX_UINT32 l_lba; ZLOX_UINT32 m_lba; ZLOX_UINT32 l_datasize; ZLOX_UINT32 m_datasize; ZLOX_UINT8 datatime[7]; ZLOX_UINT8 file_flags; ZLOX_UINT8 file_unit_size; ZLOX_UINT8 interleave_gap_size; ZLOX_UINT32 vol_seq_number; ZLOX_UINT8 file_name_length; }__attribute__((packed)); typedef struct _ZLOX_ISO_DIR_RECORD ZLOX_ISO_DIR_RECORD; typedef struct _ZLOX_ISO_CACHE { ZLOX_UINT8 * ptr; ZLOX_UINT32 lba; ZLOX_UINT32 size; }ZLOX_ISO_CACHE; typedef struct _ZLOX_ISO_PATH_TABLE_EXTDATA { ZLOX_UINT32 pt_offset; ZLOX_UINT32 datasize; }ZLOX_ISO_PATH_TABLE_EXTDATA; // 卸载iso目录,将堆中分配的相关内存资源释放掉 ZLOX_FS_NODE * zlox_unmount_iso(); // 挂载CDROM到iso目录下 ZLOX_FS_NODE * zlox_mount_iso(); #endif // _ZLOX_ISO_H_ |
// 卸载iso目录,将堆中分配的相关内存资源释放掉 ZLOX_FS_NODE * zlox_unmount_iso() { if(iso_root != ZLOX_NULL) { zlox_kfree(iso_root); iso_root = ZLOX_NULL; iso_ide_index = -1; } if(iso_path_table != ZLOX_NULL) { zlox_kfree(iso_path_table); iso_path_table = ZLOX_NULL; iso_path_table_sz = 0; } if(iso_path_table_extdata != ZLOX_NULL) { zlox_kfree(iso_path_table_extdata); iso_path_table_extdata = ZLOX_NULL; } if(iso_cache.ptr != ZLOX_NULL) { zlox_kfree(iso_cache.ptr); iso_cache.ptr = ZLOX_NULL; iso_cache.lba = 0; iso_cache.size = 0; } return iso_root; } // 挂载CDROM到iso目录下 ZLOX_FS_NODE * zlox_mount_iso() { ZLOX_SINT32 i,j; iso_root = ZLOX_NULL; for(i = 0 ; i < 4 ; i++) { // 寻找ATAPI光盘设备 if(ide_devices[i].Reserved == 0 || ide_devices[i].Type != ZLOX_IDE_ATAPI) continue; // 初始化ISO文件系统的根节点 iso_root = (ZLOX_FS_NODE *)zlox_kmalloc(sizeof(ZLOX_FS_NODE)); zlox_strcpy(iso_root->name, "iso"); iso_root->mask = iso_root->uid = iso_root->gid = iso_root->inode = iso_root->length = 0; iso_root->flags = ZLOX_FS_DIRECTORY; iso_root->read = 0; iso_root->write = 0; iso_root->open = 0; iso_root->close = 0; iso_root->readdir = &zlox_iso_readdir; iso_root->finddir = &zlox_iso_finddir; iso_root->ptr = 0; iso_root->impl = 1; //设置iso目录对应的IDE设备号,访问iso时,会使用该设备号来读写对应的ATAPI光盘设备 iso_ide_index = i; //Primary Volume Descriptor (主卷描述符,里面存储着Path Table路径表和Root根目录的LBA寻址信息) ZLOX_UINT8 * pvd = (ZLOX_UINT8 *)zlox_kmalloc(ZLOX_ATAPI_SECTOR_SIZE); //查找Primary Volume Descriptor (主卷描述符) for(j=0;;j++) { zlox_atapi_drive_read_sector(iso_ide_index,ZLOX_PVD_START_LBA + j,pvd); if(pvd[1] != ZLOX_VD_ID_1 || pvd[2] != ZLOX_VD_ID_2 || pvd[3] != ZLOX_VD_ID_3 || pvd[4] != ZLOX_VD_ID_4 || pvd[5] != ZLOX_VD_ID_5) goto err; else if(pvd[0] == ZLOX_PVD_TYPE) break; else if(pvd[0] == ZLOX_VD_TERMINATOR) goto err; } //获取根目录的directory record(目录记录,里面存储了目录的寻址等信息) ZLOX_ISO_DIR_RECORD * dir_record = (ZLOX_ISO_DIR_RECORD *)(pvd + ZLOX_PVD_ROOT_OFFSET); iso_root->inode = dir_record->l_lba; iso_root->length = dir_record->l_datasize; //将Path Table路径表缓存到iso_path_table对应的堆空间 ZLOX_UINT32 path_table_sz = *((ZLOX_UINT32 *)(pvd + ZLOX_PVD_PTSZ_OFFSET)); ZLOX_UINT32 path_table_lba = *((ZLOX_UINT32 *)(pvd + ZLOX_PVD_LPT_OFFSET)); zlox_atapi_drive_read_sector(iso_ide_index,path_table_lba,pvd); iso_path_table = (ZLOX_UINT8 *)zlox_kmalloc(path_table_sz); zlox_memcpy(iso_path_table,pvd,path_table_sz); iso_path_table_sz = path_table_sz; zlox_kfree(pvd); zlox_init_path_table_extdata(); break; err: zlox_monitor_write("kernel: iso mount err...\n"); zlox_kfree(iso_root); zlox_kfree(pvd); iso_root = ZLOX_NULL; break; } return iso_root; } |
// 从node目录节点中搜索index索引对应的文件或目录的基本信息 static ZLOX_DIRENT * zlox_iso_readdir(ZLOX_FS_NODE *node, ZLOX_UINT32 index) { ........................................... ........................................... for(i=0;i <= index;i++) { dir_offset = (ZLOX_UINT32)dir_record - (ZLOX_UINT32)iso_cache.ptr; dir_sector = dir_offset / ZLOX_ATAPI_SECTOR_SIZE + 1; if(dir_offset >= cur_datasize) return 0; if(dir_record->length == 0) { if(dir_sector == cur_datasize / ZLOX_ATAPI_SECTOR_SIZE) return 0; // 当目录的extents(数据块)的某个扇区快用完时,它会从下一个扇区开始放置数据,所以这里需要直接跳到下一个扇区 dir_record = (ZLOX_ISO_DIR_RECORD *)(iso_cache.ptr + (dir_sector * ZLOX_ATAPI_SECTOR_SIZE)); } if(i < index) dir_record = (ZLOX_ISO_DIR_RECORD *)((ZLOX_UINT8 *)dir_record + dir_record->length); } ........................................... ........................................... } |