Serenity Operating System
1/*
2 * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/EnumBits.h>
10#include <AK/Types.h>
11
12namespace Kernel {
13
14namespace ISO {
15
16// The implemented spec here is ECMA 119, available at:
17// https://www.ecma-international.org/wp-content/uploads/ECMA-119_4th_edition_june_2019.pdf
18
19template<typename T>
20struct [[gnu::packed]] LittleAndBigEndian {
21 T little;
22 T big;
23};
24
25// 8.4.26.1 Date and Time Format
26struct [[gnu::packed]] AsciiDateAndTime {
27 // All of these fields are ASCII digits. :^)
28 u8 year[4];
29 u8 month[2];
30 u8 day[2];
31
32 u8 hour[2];
33 u8 minute[2];
34 u8 second[2];
35 u8 hundredths_of_second[2];
36
37 // From OSDev wiki:
38 // Time zone offset from GMT in 15 minute intervals, starting at
39 // interval -48 (west) and running up to interval 52 (east). So value 0
40 // indicates interval -48 which equals GMT-12 hours, and value 100
41 // indicates interval 52 which equals GMT+13 hours.
42 u8 timezone_offset;
43};
44static_assert(sizeof(AsciiDateAndTime) == 17);
45
46// 9.1.5 Recording Date and Time (BP 19 to 25)
47struct [[gnu::packed]] NumericalDateAndTime {
48 u8 years_since_1900;
49 u8 month;
50 u8 day;
51 u8 hour;
52 u8 minute;
53 u8 second;
54 // Same format as AsciiDateAndTime.
55 u8 timezone_offset;
56};
57static_assert(sizeof(NumericalDateAndTime) == 7);
58
59// --- Path Table ---
60
61// 9.4 Format of a Path Table Record
62struct [[gnu::packed]] PathTableRecord {
63 u8 directory_identifier_length;
64 u8 extended_attribute_record_length;
65 u32 extent_location;
66 u16 parent_directory_number;
67
68 u8 directory_identifier[];
69};
70static_assert(sizeof(PathTableRecord) == 8);
71
72// --- Extended Attribute Record ---
73
74// 9.5.3 Permissions
75enum class ExtendedPermissions : u16 {
76 SystemGroupReadable = 1 << 0,
77 SystemGroupExecutable = 1 << 2,
78 UserReadable = 1 << 4,
79 UserExecutable = 1 << 6,
80 GroupReadable = 1 << 8,
81 GroupExecutable = 1 << 10,
82 OtherReadable = 1 << 12,
83 OtherExecutable = 1 << 14,
84};
85AK_ENUM_BITWISE_OPERATORS(ExtendedPermissions);
86
87// 9.5.8 Record Format
88enum class RecordFormat : u8 {
89 NotSpecified = 0,
90 FixedLengthRecords = 1,
91 LittleEndianVariableRecords = 2,
92 BigEndianVariableRecords = 3,
93 // 4-127 are reserved for future standardization.
94 // 128-255 are reserved for system use.
95};
96
97// 9.5.9 Record Attributes
98enum class RecordAttributes : u8 {
99 // This value means the record is stored like: \n123456\r.
100 LfCrDelimited = 0,
101 FortranVerticalSpacing = 1,
102 ContainsControlInformation = 2,
103 // 3-255 are reserved for future standardization.
104};
105
106// 9.5 Format of an Extended Attribute Record
107struct [[gnu::packed]] ExtendedAttributeRecord {
108 LittleAndBigEndian<u16> owner_identification;
109 LittleAndBigEndian<u16> group_identification;
110 ExtendedPermissions permissions;
111
112 AsciiDateAndTime file_creation_date_and_time;
113 AsciiDateAndTime file_modification_date_and_time;
114 AsciiDateAndTime file_expiration_date_and_time;
115 AsciiDateAndTime file_effective_date_and_time;
116
117 RecordFormat record_format;
118 u8 record_attributes;
119
120 LittleAndBigEndian<u16> record_length;
121
122 u8 system_identifier[32];
123 u8 system_use[64];
124
125 u8 extended_attribute_record_version;
126 u8 escape_sequence_length;
127
128 u8 reserved[64];
129
130 LittleAndBigEndian<u16> application_use_length;
131
132 // NOTE: Application use is immediately followed by escape sequences (no
133 // padding).
134 u8 application_use_and_escape_sequences[];
135};
136static_assert(sizeof(ExtendedAttributeRecord) == 250);
137
138// --- Files and Directories ---
139
140// 9.1.6 File Flags
141enum class FileFlags : u8 {
142 Hidden = 1 << 0, // The "existence" flag
143 Directory = 1 << 1,
144 AssociatedFile = 1 << 2,
145 Record = 1 << 3,
146 Protection = 1 << 4,
147 // 5 and 6 are reserved.
148 MultiExtent = 1 << 7,
149};
150
151AK_ENUM_BITWISE_OPERATORS(FileFlags);
152
153struct [[gnu::packed]] DirectoryRecordHeader {
154 u8 length;
155 u8 extended_attribute_record_length;
156 LittleAndBigEndian<u32> extent_location;
157 LittleAndBigEndian<u32> data_length;
158 NumericalDateAndTime recording_date_and_time;
159 FileFlags file_flags;
160 u8 file_unit_size;
161 u8 interleave_gap_size;
162 LittleAndBigEndian<u16> volume_sequence_number;
163 u8 file_identifier_length;
164
165 // NOTE: The file identifier itself is of variable length, so it and the
166 // fields following it are not included in this struct. Instead, they are:
167 //
168 // 34 to (33+file_identifier_length) - file identifier
169 // 1 byte of padding, if file_identifier_length is even
170 //
171 // The remaining bytes are system use (ISO9660 extensions).
172};
173static_assert(sizeof(DirectoryRecordHeader) == 33);
174
175// --- Volume Descriptors ---
176
177enum class VolumeDescriptorType : u8 {
178 BootRecord = 0,
179 PrimaryVolumeDescriptor = 1,
180 SupplementaryOrEnhancedVolumeDescriptor = 2,
181 VolumePartitionDescriptor = 3,
182 // 4-254 are reserved.
183 VolumeDescriptorSetTerminator = 255,
184};
185
186// 8.1 Format of a Volume Descriptor
187struct [[gnu::packed]] VolumeDescriptorHeader {
188 VolumeDescriptorType type;
189 // NOTE: Contains exactly "CD001".
190 u8 identifier[5];
191 u8 version;
192};
193static_assert(sizeof(VolumeDescriptorHeader) == 7);
194
195// 8.2 Boot Record
196struct [[gnu::packed]] BootRecord {
197 VolumeDescriptorHeader header;
198 u8 boot_system_identifier[32];
199 u8 boot_identifier[32];
200 u8 boot_system_use[1977];
201};
202static_assert(sizeof(BootRecord) == 2048);
203
204// 8.3 Volume Descriptor Set Terminator
205struct [[gnu::packed]] VolumeDescriptorSetTerminator {
206 VolumeDescriptorHeader header;
207 u8 zeros[2041];
208};
209static_assert(sizeof(VolumeDescriptorSetTerminator) == 2048);
210
211// 8.4 Primary Volume Descriptor
212struct [[gnu::packed]] PrimaryVolumeDescriptor {
213 VolumeDescriptorHeader header;
214 u8 unused1;
215 u8 system_identifier[32];
216 u8 volume_identifier[32];
217 u64 unused2;
218 LittleAndBigEndian<u32> volume_space_size;
219 u8 unused3[32];
220 LittleAndBigEndian<u16> volume_set_size;
221 LittleAndBigEndian<u16> volume_sequence_number;
222 LittleAndBigEndian<u16> logical_block_size;
223 LittleAndBigEndian<u32> path_table_size;
224
225 u32 l_path_table_occurrence_location;
226 u32 l_path_table_optional_occurrence_location;
227 u32 m_path_table_occurrence_location;
228 u32 m_path_table_optional_occurrence_location;
229
230 DirectoryRecordHeader root_directory_record_header;
231 u8 root_directory_identifier; // Exactly 0x00.
232
233 u8 volume_set_identifier[128];
234 u8 publisher_identifier[128];
235 u8 data_preparer_identifier[128];
236 u8 application_identifier[128];
237
238 u8 copyright_file_identifier[37];
239 u8 abstract_file_identifier[37];
240 u8 bibliographic_file_identifier[37];
241
242 AsciiDateAndTime volume_creation_date_and_time;
243 AsciiDateAndTime volume_modification_date_and_time;
244 AsciiDateAndTime volume_expiration_date_and_time;
245 AsciiDateAndTime volume_effective_date_and_time;
246
247 u8 file_structure_version; // Always 0x01.
248 u8 unused4;
249 u8 application_use[512];
250 u8 reserved[653];
251};
252static_assert(sizeof(PrimaryVolumeDescriptor) == 2048);
253
254// 8.6 Volume Partition Descriptor
255struct [[gnu::packed]] VolumePartitionDescriptor {
256 VolumeDescriptorHeader header;
257 u8 unused;
258
259 u8 system_identifier[32];
260 u8 volume_partition_identifier[32];
261 LittleAndBigEndian<u32> volume_partition_location;
262 LittleAndBigEndian<u32> volume_partition_size;
263
264 u8 system_use[1960];
265};
266static_assert(sizeof(VolumePartitionDescriptor) == 2048);
267
268}
269
270}