2 * This file contains support for Rock Ridge Interchange Protocol (RRIP)
3 * extension to ISO 9660.
9 #ifdef ISO9660_OPTION_ROCKRIDGE
11 void parse_susp_rock_ridge_plcl(struct rrii_dir_record
*dir
, u32_t block
) {
12 struct inode
*rep_inode
;
14 struct iso9660_dir_record
*dir_rec
;
15 struct dir_extent extent
;
16 struct inode_dir_entry dummy_dir_entry
;
17 size_t dummy_offset
= 0;
19 /* Check if inode wasn't already parsed. */
20 rep_inode
= inode_cache_get(block
);
21 if (rep_inode
!= NULL
) {
22 rep_inode
->i_refcount
++;
23 dir
->reparented_inode
= rep_inode
;
27 /* Peek ahead to build extent for read_inode. */
28 if (lmfs_get_block(&bp
, fs_dev
, block
, NORMAL
) != OK
)
31 dir_rec
= (struct iso9660_dir_record
*)b_data(bp
);
33 extent
.location
= block
;
34 extent
.length
= dir_rec
->data_length_l
/ v_pri
.logical_block_size_l
;
35 if (dir_rec
->data_length_l
% v_pri
.logical_block_size_l
)
40 memset(&dummy_dir_entry
, 0, sizeof(struct inode_dir_entry
));
41 /* XXX what if this fails? */
42 read_inode(&dummy_dir_entry
, &extent
, &dummy_offset
);
43 free(dummy_dir_entry
.r_name
);
44 dir
->reparented_inode
= dummy_dir_entry
.i_node
;
47 void parse_susp_rock_ridge_sl(struct rrii_dir_record
*dir
, char *buffer
, int length
)
49 /* Parse a Rock Ridge SUSP symbolic link entry (SL). */
52 u8_t flags
, component_length
;
54 while (offset
+ 2 <= length
) {
55 flags
= *((u8_t
*)(buffer
+ offset
));
56 component_length
= *((u8_t
*)(buffer
+ offset
+ 1));
58 /* Add directory separator if necessary. */
59 if (strcmp(dir
->slink_rrip
, "") != 0 &&
60 strcmp(dir
->slink_rrip
, "/") != 0) {
61 slink_size
= strlen(dir
->slink_rrip
);
62 if (slink_size
+ 2 >= ISO9660_RRIP_MAX_FILE_ID_LEN
)
65 dir
->slink_rrip
[slink_size
++] = '/';
66 dir
->slink_rrip
[slink_size
] = '\0';
69 slink_size
= strlen(dir
->slink_rrip
);
71 switch (flags
& 0xF) {
75 * Directory path component.
76 * Check if component fits within SL entry and
77 * within symbolic link field.
79 if ((component_length
> length
- offset
) ||
80 (slink_size
+ component_length
+ 1 >=
81 ISO9660_RRIP_MAX_FILE_ID_LEN
)) {
85 strlcat(&dir
->slink_rrip
[slink_size
],
87 component_length
+ 1);
92 /* Current directory path component. */
94 ISO9660_RRIP_MAX_FILE_ID_LEN
) {
98 strcat(&dir
->slink_rrip
[slink_size
], ".");
103 /* Parent directory path component. */
104 if (slink_size
+ 3 >=
105 ISO9660_RRIP_MAX_FILE_ID_LEN
) {
109 strcat(&dir
->slink_rrip
[slink_size
], "..");
114 /* Root directory path component relative to
115 the current process. */
116 if (slink_size
+ 2 >=
117 ISO9660_RRIP_MAX_FILE_ID_LEN
) {
121 strcat(&dir
->slink_rrip
[slink_size
], "/");
126 /* Unsupported/invalid flags. */
131 offset
+= component_length
+ 2;
135 int parse_susp_rock_ridge(struct rrii_dir_record
*dir
, char *buffer
)
137 /* Parse Rock Ridge SUSP entries for a directory entry. */
138 char susp_signature
[2];
142 int rrii_name_current_size
;
143 int rrii_name_append_size
;
146 u32_t rrii_pn_rdev_major
;
147 u32_t rrii_pn_rdev_minor
;
148 mode_t rrii_px_posix_mode
;
149 u32_t rrii_pcl_block
;
151 susp_signature
[0] = buffer
[0];
152 susp_signature
[1] = buffer
[1];
153 susp_length
= *((u8_t
*)buffer
+ 2);
154 susp_version
= *((u8_t
*)buffer
+ 3);
156 if ((susp_signature
[0] == 'P') && (susp_signature
[1] == 'X') &&
157 (susp_length
>= 36) && (susp_version
>= 1)) {
158 /* POSIX file mode, UID and GID. */
159 dir
->d_mode
= *((u32_t
*)(buffer
+ 4));
160 dir
->uid
= *((u32_t
*)(buffer
+ 20));
161 dir
->gid
= *((u32_t
*)(buffer
+ 28));
165 else if ((susp_signature
[0] == 'P') && (susp_signature
[1] == 'N') &&
166 (susp_length
>= 20) && (susp_version
>= 1)) {
167 /* Device ID (for character or block special inode). */
170 * XXX: Specific to how Minix ISO is generated, will have to
171 * investigate why makefs does that later.
174 rrii_pn_rdev_major
= *((u32_t
*)(buffer
+ 4));
175 rrii_pn_rdev_minor
= *((u32_t
*)(buffer
+ 12));
177 rrii_pn_rdev_major
= *((u32_t
*)(buffer
+ 12)) >> 8;
178 rrii_pn_rdev_minor
= *((u32_t
*)(buffer
+ 12)) & 0xFF;
180 dir
->rdev
= makedev(rrii_pn_rdev_major
, rrii_pn_rdev_minor
);
184 else if ((susp_signature
[0] == 'S') && (susp_signature
[1] == 'L') &&
185 (susp_length
> 5) && (susp_version
>= 1)) {
186 /* Symbolic link target. Multiple entries may be used to
187 concatenate the complete path target. */
188 parse_susp_rock_ridge_sl(dir
, buffer
+ 5, susp_length
- 5);
192 else if ((susp_signature
[0] == 'N') && (susp_signature
[1] == 'M') &&
193 (susp_length
> 5) && (susp_version
>= 1)) {
194 /* Alternate POSIX name. Multiple entries may be used to
195 concatenate the complete filename. */
196 rrii_name_current_size
= strlen(dir
->file_id_rrip
);
197 rrii_name_append_size
= susp_length
- 5;
199 /* Concatenate only if name component fits. */
200 if (rrii_name_current_size
+ rrii_name_append_size
+ 1 <
201 ISO9660_RRIP_MAX_FILE_ID_LEN
) {
202 strlcpy(dir
->file_id_rrip
+ rrii_name_current_size
,
203 buffer
+ 5, rrii_name_append_size
+1);
208 else if ((susp_signature
[0] == 'P') && (susp_signature
[1] == 'L') &&
209 (susp_length
>= 12) && (susp_version
>= 1)) {
210 /* Reparenting ".." directory entry. */
211 rrii_pcl_block
= *((u32_t
*)(buffer
+ 4));
212 parse_susp_rock_ridge_plcl(dir
, rrii_pcl_block
);
216 else if ((susp_signature
[0] == 'C') && (susp_signature
[1] == 'L') &&
217 (susp_length
>= 12) && (susp_version
>= 1)) {
218 /* Reorganize deep directory entry. */
219 rrii_pcl_block
= *((u32_t
*)(buffer
+ 4));
220 parse_susp_rock_ridge_plcl(dir
, rrii_pcl_block
);
224 else if ((susp_signature
[0] == 'R') && (susp_signature
[1] == 'E')) {
229 else if ((susp_signature
[0] == 'T') && (susp_signature
[1] == 'F') &&
230 (susp_length
>= 5) && (susp_version
>= 1)) {
231 /* POSIX timestamp. */
232 rrii_tf_flags
= buffer
[5];
236 * ISO 9660 17-byte time format.
237 * FIXME: 17-byte time format not supported in TF entry.
239 if (rrii_tf_flags
& (1 << 7)) { }
241 /* ISO 9660 7-byte time format. */
244 if ((rrii_tf_flags
& (1 << 0)) &&
245 (rrii_tf_offset
+ ISO9660_SIZE_DATE7
<= susp_length
)) {
246 memcpy(dir
->birthtime
, buffer
+rrii_tf_offset
,
248 rrii_tf_offset
+= ISO9660_SIZE_DATE7
;
251 /* Modification time */
252 if ((rrii_tf_flags
& (1 << 1)) &&
253 (rrii_tf_offset
+ ISO9660_SIZE_DATE7
<= susp_length
)) {
254 memcpy(dir
->mtime
, buffer
+rrii_tf_offset
,
256 rrii_tf_offset
+= ISO9660_SIZE_DATE7
;
259 /* Last access time. */
260 if ((rrii_tf_flags
& (1 << 2)) &&
261 (rrii_tf_offset
+ ISO9660_SIZE_DATE7
<= susp_length
)) {
262 memcpy(dir
->atime
, buffer
+rrii_tf_offset
,
264 rrii_tf_offset
+= ISO9660_SIZE_DATE7
;
267 /* Last attribute change time. */
268 if ((rrii_tf_flags
& (1 << 3)) &&
269 (rrii_tf_offset
+ ISO9660_SIZE_DATE7
<= susp_length
)) {
270 memcpy(dir
->ctime
, buffer
+rrii_tf_offset
,
272 rrii_tf_offset
+= ISO9660_SIZE_DATE7
;
275 /* The rest is ignored. */
280 else if ((susp_signature
[0] == 'S') && (susp_signature
[1] == 'F')) {
285 /* Not a Rock Ridge entry. */