xref: /minix/minix/fs/isofs/susp_rock_ridge.c (revision 0a6a1f1d)
1 /*
2  * This file contains support for Rock Ridge Interchange Protocol (RRIP)
3  * extension to ISO 9660.
4  */
5 
6 #include "inc.h"
7 #include <sys/stat.h>
8 
9 #ifdef ISO9660_OPTION_ROCKRIDGE
10 
11 void parse_susp_rock_ridge_plcl(struct rrii_dir_record *dir, u32_t block) {
12 	struct inode *rep_inode;
13 	struct buf *bp;
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;
18 
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;
24 		return;
25 	}
26 
27 	/* Peek ahead to build extent for read_inode. */
28 	if (lmfs_get_block(&bp, fs_dev, block, NORMAL) != OK)
29 		return;
30 
31 	dir_rec = (struct iso9660_dir_record*)b_data(bp);
32 
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)
36 		extent.length++;
37 	extent.next = NULL;
38 	lmfs_put_block(bp);
39 
40 	memset(&dummy_dir_entry, 0, sizeof(struct inode_dir_entry));
41 	read_inode(&dummy_dir_entry, &extent, &dummy_offset);
42 	free(dummy_dir_entry.r_name);
43 	dir->reparented_inode = dummy_dir_entry.i_node;
44 }
45 
46 void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length)
47 {
48 	/* Parse a Rock Ridge SUSP symbolic link entry (SL). */
49 	int offset = 0;
50 	int slink_size;
51 	u8_t flags, component_length;
52 
53 	while (offset + 2 <= length) {
54 		flags = *((u8_t*)(buffer + offset));
55 		component_length = *((u8_t*)(buffer + offset + 1));
56 
57 		/* Add directory separator if necessary. */
58 		if (strcmp(dir->slink_rrip, "") != 0 &&
59 		    strcmp(dir->slink_rrip, "/") != 0) {
60 			slink_size = strlen(dir->slink_rrip);
61 			if (slink_size + 2 >= ISO9660_RRIP_MAX_FILE_ID_LEN)
62 				return;
63 
64 			dir->slink_rrip[slink_size++] = '/';
65 			dir->slink_rrip[slink_size] = '\0';
66 		}
67 		else
68 			slink_size = strlen(dir->slink_rrip);
69 
70 		switch (flags & 0xF) {
71 			case 0:
72 			case 1: {
73 				/*
74 				 * Directory path component.
75 				 * Check if component fits within SL entry and
76 				 * within symbolic link field.
77 				 */
78 				if ((component_length > length - offset) ||
79 				    (slink_size + component_length + 1 >=
80 				    ISO9660_RRIP_MAX_FILE_ID_LEN)) {
81 					return;
82 				}
83 
84 				strlcat(&dir->slink_rrip[slink_size],
85 				        buffer + offset + 2,
86 				        component_length + 1);
87 
88 				break;
89 			}
90 			case 2: {
91 				/* Current directory path component. */
92 				if (slink_size + 2 >=
93 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
94 					return;
95 				}
96 
97 				strcat(&dir->slink_rrip[slink_size], ".");
98 
99 				break;
100 			}
101 			case 4: {
102 				/* Parent directory path component. */
103 				if (slink_size + 3 >=
104 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
105 					return;
106 				}
107 
108 				strcat(&dir->slink_rrip[slink_size], "..");
109 
110 				break;
111 			}
112 			case 8: {
113 				/* Root directory path component relative to
114 				   the current process. */
115 				if (slink_size + 2 >=
116 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
117 					return;
118 				}
119 
120 				strcat(&dir->slink_rrip[slink_size], "/");
121 
122 				break;
123 			}
124 			default: {
125 				/* Unsupported/invalid flags. */
126 				return;
127 			}
128 		}
129 
130 		offset += component_length + 2;
131 	}
132 }
133 
134 int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer)
135 {
136 	/* Parse Rock Ridge SUSP entries for a directory entry. */
137 	char susp_signature[2];
138 	u8_t susp_length;
139 	u8_t susp_version;
140 
141 	int rrii_name_current_size;
142 	int rrii_name_append_size;
143 	int rrii_tf_flags;
144 	int rrii_tf_offset;
145 	u32_t rrii_pn_rdev_major;
146 	u32_t rrii_pn_rdev_minor;
147 	mode_t rrii_px_posix_mode;
148 	u32_t rrii_pcl_block;
149 
150 	susp_signature[0] = buffer[0];
151 	susp_signature[1] = buffer[1];
152 	susp_length = *((u8_t*)buffer + 2);
153 	susp_version = *((u8_t*)buffer + 3);
154 
155 	if ((susp_signature[0] == 'P') && (susp_signature[1] == 'X') &&
156 	    (susp_length >= 36) && (susp_version >= 1)) {
157 		/* POSIX file mode, UID and GID. */
158 		dir->d_mode = *((u32_t*)(buffer + 4));
159 		dir->uid = *((u32_t*)(buffer + 20));
160 		dir->gid = *((u32_t*)(buffer + 28));
161 
162 		return OK;
163 	}
164 	else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'N') &&
165 	         (susp_length >= 20) && (susp_version >= 1)) {
166 		/* Device ID (for character or block special inode). */
167 
168 		/*
169 		 * XXX: Specific to how Minix ISO is generated, will have to
170 		 * investigate why makefs does that later.
171 		 */
172 #if 0
173 		rrii_pn_rdev_major = *((u32_t*)(buffer + 4));
174 		rrii_pn_rdev_minor = *((u32_t*)(buffer + 12));
175 #else
176 		rrii_pn_rdev_major = *((u32_t*)(buffer + 12)) >> 8;
177 		rrii_pn_rdev_minor = *((u32_t*)(buffer + 12)) & 0xFF;
178 #endif
179 		dir->rdev = makedev(rrii_pn_rdev_major, rrii_pn_rdev_minor);
180 
181 		return OK;
182 	}
183 	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'L') &&
184 	         (susp_length > 5) && (susp_version >= 1)) {
185 		/* Symbolic link target. Multiple entries may be used to
186 		   concatenate the complete path target. */
187 		parse_susp_rock_ridge_sl(dir, buffer + 5, susp_length - 5);
188 
189 		return OK;
190 	}
191 	else if ((susp_signature[0] == 'N') && (susp_signature[1] == 'M') &&
192 	         (susp_length > 5) && (susp_version >= 1)) {
193 		/* Alternate POSIX name. Multiple entries may be used to
194 		   concatenate the complete filename. */
195 		rrii_name_current_size = strlen(dir->file_id_rrip);
196 		rrii_name_append_size = susp_length - 5;
197 
198 		/* Concatenate only if name component fits. */
199 		if (rrii_name_current_size + rrii_name_append_size + 1 <
200 		    ISO9660_RRIP_MAX_FILE_ID_LEN) {
201 			strlcpy(dir->file_id_rrip + rrii_name_current_size,
202 			    buffer + 5, rrii_name_append_size+1);
203 		}
204 
205 		return OK;
206 	}
207 	else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L') &&
208 	         (susp_length >= 12) && (susp_version >= 1)) {
209 		/* Reparenting ".." directory entry. */
210 		rrii_pcl_block = *((u32_t*)(buffer + 4));
211 		parse_susp_rock_ridge_plcl(dir, rrii_pcl_block);
212 
213 		return OK;
214 	}
215 	else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L') &&
216 	         (susp_length >= 12) && (susp_version >= 1)) {
217 		/* Reorganize deep directory entry. */
218 		rrii_pcl_block = *((u32_t*)(buffer + 4));
219 		parse_susp_rock_ridge_plcl(dir, rrii_pcl_block);
220 
221 		return OK;
222 	}
223 	else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) {
224 		/* Ignored, skip. */
225 
226 		return OK;
227 	}
228 	else if ((susp_signature[0] == 'T') && (susp_signature[1] == 'F') &&
229 	         (susp_length >= 5) && (susp_version >= 1)) {
230 		/* POSIX timestamp. */
231 		rrii_tf_flags = buffer[5];
232 		rrii_tf_offset = 5;
233 
234 		/*
235 		 * ISO 9660 17-byte time format.
236 		 * FIXME: 17-byte time format not supported in TF entry.
237 		 */
238 		if (rrii_tf_flags & (1 << 7)) { }
239 
240 		/* ISO 9660 7-byte time format. */
241 		else {
242 			/* Creation time  */
243 			if ((rrii_tf_flags & (1 << 0)) &&
244 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
245 				memcpy(dir->birthtime, buffer+rrii_tf_offset,
246 				       ISO9660_SIZE_DATE7);
247 				rrii_tf_offset += ISO9660_SIZE_DATE7;
248 			}
249 
250 			/* Modification time */
251 			if ((rrii_tf_flags & (1 << 1)) &&
252 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
253 				memcpy(dir->mtime, buffer+rrii_tf_offset,
254 				       ISO9660_SIZE_DATE7);
255 				rrii_tf_offset += ISO9660_SIZE_DATE7;
256 			}
257 
258 			/* Last access time. */
259 			if ((rrii_tf_flags & (1 << 2)) &&
260 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
261 				memcpy(dir->atime, buffer+rrii_tf_offset,
262 				       ISO9660_SIZE_DATE7);
263 				rrii_tf_offset += ISO9660_SIZE_DATE7;
264 			}
265 
266 			/* Last attribute change time. */
267 			if ((rrii_tf_flags & (1 << 3)) &&
268 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
269 				memcpy(dir->ctime, buffer+rrii_tf_offset,
270 				       ISO9660_SIZE_DATE7);
271 				rrii_tf_offset += ISO9660_SIZE_DATE7;
272 			}
273 
274 			/* The rest is ignored. */
275 		}
276 
277 		return OK;
278 	}
279 	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'F')) {
280 		/* Ignored, skip. */
281 		return OK;
282 	}
283 
284 	/* Not a Rock Ridge entry. */
285 	return EINVAL;
286 }
287 
288 #endif
289