xref: /minix/minix/fs/isofs/susp_rock_ridge.c (revision 2a404668)
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 	/* 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;
45 }
46 
47 void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length)
48 {
49 	/* Parse a Rock Ridge SUSP symbolic link entry (SL). */
50 	int offset = 0;
51 	int slink_size;
52 	u8_t flags, component_length;
53 
54 	while (offset + 2 <= length) {
55 		flags = *((u8_t*)(buffer + offset));
56 		component_length = *((u8_t*)(buffer + offset + 1));
57 
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)
63 				return;
64 
65 			dir->slink_rrip[slink_size++] = '/';
66 			dir->slink_rrip[slink_size] = '\0';
67 		}
68 		else
69 			slink_size = strlen(dir->slink_rrip);
70 
71 		switch (flags & 0xF) {
72 			case 0:
73 			case 1: {
74 				/*
75 				 * Directory path component.
76 				 * Check if component fits within SL entry and
77 				 * within symbolic link field.
78 				 */
79 				if ((component_length > length - offset) ||
80 				    (slink_size + component_length + 1 >=
81 				    ISO9660_RRIP_MAX_FILE_ID_LEN)) {
82 					return;
83 				}
84 
85 				strlcat(&dir->slink_rrip[slink_size],
86 				        buffer + offset + 2,
87 				        component_length + 1);
88 
89 				break;
90 			}
91 			case 2: {
92 				/* Current directory path component. */
93 				if (slink_size + 2 >=
94 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
95 					return;
96 				}
97 
98 				strcat(&dir->slink_rrip[slink_size], ".");
99 
100 				break;
101 			}
102 			case 4: {
103 				/* Parent directory path component. */
104 				if (slink_size + 3 >=
105 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
106 					return;
107 				}
108 
109 				strcat(&dir->slink_rrip[slink_size], "..");
110 
111 				break;
112 			}
113 			case 8: {
114 				/* Root directory path component relative to
115 				   the current process. */
116 				if (slink_size + 2 >=
117 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
118 					return;
119 				}
120 
121 				strcat(&dir->slink_rrip[slink_size], "/");
122 
123 				break;
124 			}
125 			default: {
126 				/* Unsupported/invalid flags. */
127 				return;
128 			}
129 		}
130 
131 		offset += component_length + 2;
132 	}
133 }
134 
135 int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer)
136 {
137 	/* Parse Rock Ridge SUSP entries for a directory entry. */
138 	char susp_signature[2];
139 	u8_t susp_length;
140 	u8_t susp_version;
141 
142 	int rrii_name_current_size;
143 	int rrii_name_append_size;
144 	int rrii_tf_flags;
145 	int rrii_tf_offset;
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;
150 
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);
155 
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));
162 
163 		return OK;
164 	}
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). */
168 
169 		/*
170 		 * XXX: Specific to how Minix ISO is generated, will have to
171 		 * investigate why makefs does that later.
172 		 */
173 #if 0
174 		rrii_pn_rdev_major = *((u32_t*)(buffer + 4));
175 		rrii_pn_rdev_minor = *((u32_t*)(buffer + 12));
176 #else
177 		rrii_pn_rdev_major = *((u32_t*)(buffer + 12)) >> 8;
178 		rrii_pn_rdev_minor = *((u32_t*)(buffer + 12)) & 0xFF;
179 #endif
180 		dir->rdev = makedev(rrii_pn_rdev_major, rrii_pn_rdev_minor);
181 
182 		return OK;
183 	}
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);
189 
190 		return OK;
191 	}
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;
198 
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);
204 		}
205 
206 		return OK;
207 	}
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);
213 
214 		return OK;
215 	}
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);
221 
222 		return OK;
223 	}
224 	else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) {
225 		/* Ignored, skip. */
226 
227 		return OK;
228 	}
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];
233 		rrii_tf_offset = 5;
234 
235 		/*
236 		 * ISO 9660 17-byte time format.
237 		 * FIXME: 17-byte time format not supported in TF entry.
238 		 */
239 		if (rrii_tf_flags & (1 << 7)) { }
240 
241 		/* ISO 9660 7-byte time format. */
242 		else {
243 			/* Creation time  */
244 			if ((rrii_tf_flags & (1 << 0)) &&
245 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
246 				memcpy(dir->birthtime, buffer+rrii_tf_offset,
247 				       ISO9660_SIZE_DATE7);
248 				rrii_tf_offset += ISO9660_SIZE_DATE7;
249 			}
250 
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,
255 				       ISO9660_SIZE_DATE7);
256 				rrii_tf_offset += ISO9660_SIZE_DATE7;
257 			}
258 
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,
263 				       ISO9660_SIZE_DATE7);
264 				rrii_tf_offset += ISO9660_SIZE_DATE7;
265 			}
266 
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,
271 				       ISO9660_SIZE_DATE7);
272 				rrii_tf_offset += ISO9660_SIZE_DATE7;
273 			}
274 
275 			/* The rest is ignored. */
276 		}
277 
278 		return OK;
279 	}
280 	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'F')) {
281 		/* Ignored, skip. */
282 		return OK;
283 	}
284 
285 	/* Not a Rock Ridge entry. */
286 	return EINVAL;
287 }
288 
289 #endif
290