xref: /minix/minix/fs/isofs/susp_rock_ridge.c (revision 83133719)
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 void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length)
10 {
11 	/* Parse a Rock Ridge SUSP symbolic link entry (SL). */
12 	int offset = 0;
13 	int slink_size;
14 	u8_t flags, component_length;
15 
16 	while (offset + 2 <= length) {
17 		flags = *((u8_t*)(buffer + offset));
18 		component_length = *((u8_t*)(buffer + offset + 1));
19 
20 		/* Add directory separator if necessary. */
21 		if (dir->slink_rrip[0] != '\0') {
22 			slink_size = strlen(dir->slink_rrip);
23 			if (slink_size + 2 >= ISO9660_RRIP_MAX_FILE_ID_LEN)
24 				return;
25 
26 			dir->slink_rrip[slink_size] = '/';
27 			slink_size++;
28 		}
29 		else
30 			slink_size = strlen(dir->slink_rrip);
31 
32 		switch (flags & 0xF) {
33 			case 0:
34 			case 1: {
35 				/*
36 				 * Directory path component.
37 				 * Check if component fits within SL entry and
38 				 * within symbolic link field.
39 				 */
40 				if ((component_length > length - offset) ||
41 				    (slink_size + component_length + 1 >=
42 				    ISO9660_RRIP_MAX_FILE_ID_LEN)) {
43 					return;
44 				}
45 
46 				strlcpy(dir->slink_rrip + slink_size,
47 				    buffer + offset + 2, component_length+1);
48 
49 				break;
50 			}
51 			case 2: {
52 				/* Current directory path component. */
53 				if (slink_size + 2 >=
54 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
55 					return;
56 				}
57 
58 				strcat(dir->slink_rrip + slink_size, ".");
59 
60 				break;
61 			}
62 			case 4: {
63 				/* Parent directory path component. */
64 				if (slink_size + 3 >=
65 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
66 					return;
67 				}
68 
69 				strcat(dir->slink_rrip + slink_size, "..");
70 
71 				break;
72 			}
73 			case 8: {
74 				/* Root directory path component relative to
75 				   the current process. */
76 				if (slink_size + 2 >=
77 				    ISO9660_RRIP_MAX_FILE_ID_LEN) {
78 					return;
79 				}
80 
81 				strcat(dir->slink_rrip + slink_size, "/");
82 
83 				break;
84 			}
85 			default: {
86 				/* Unsupported/invalid flags. */
87 				return;
88 			}
89 		}
90 
91 		offset += component_length + 2;
92 	}
93 }
94 
95 int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer)
96 {
97 	/* Parse Rock Ridge SUSP entries for a directory entry. */
98 	char susp_signature[2];
99 	u8_t susp_length;
100 	u8_t susp_version;
101 
102 	int rrii_name_current_size;
103 	int rrii_name_append_size;
104 	int rrii_tf_flags;
105 	int rrii_tf_offset;
106 	u32_t rrii_pn_rdev_major;
107 	u32_t rrii_pn_rdev_minor;
108 	mode_t rrii_px_posix_mode;
109 
110 	susp_signature[0] = buffer[0];
111 	susp_signature[1] = buffer[1];
112 	susp_length = *((u8_t*)buffer + 2);
113 	susp_version = *((u8_t*)buffer + 3);
114 
115 	if ((susp_signature[0] == 'P') && (susp_signature[1] == 'X') &&
116 	    (susp_length >= 36) && (susp_version >= 1)) {
117 		/* POSIX file mode, UID and GID. */
118 		rrii_px_posix_mode = *((u32_t*)(buffer + 4));
119 
120 		/* Check if file mode is supported by isofs. */
121 		switch (rrii_px_posix_mode & _S_IFMT) {
122 			case S_IFCHR:
123 			case S_IFBLK:
124 			case S_IFREG:
125 			case S_IFDIR:
126 			case S_IFLNK: {
127 				dir->d_mode = rrii_px_posix_mode & _S_IFMT;
128 				break;
129 			}
130 			default: {
131 				/* Fall back to what ISO 9660 said. */
132 				dir->d_mode &= _S_IFMT;
133 				break;
134 			}
135 		}
136 
137 		dir->d_mode |= rrii_px_posix_mode & 07777;
138 		dir->uid = *((u32_t*)(buffer + 20));
139 		dir->gid = *((u32_t*)(buffer + 28));
140 
141 		return OK;
142 	}
143 	else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'N') &&
144 	         (susp_length >= 20) && (susp_version >= 1)) {
145 		/* Device ID (for character or block special inode). */
146 		rrii_pn_rdev_major = *((u32_t*)(buffer + 4));
147 		rrii_pn_rdev_minor = *((u32_t*)(buffer + 12));
148 
149 		dir->rdev = makedev(rrii_pn_rdev_major, rrii_pn_rdev_minor);
150 
151 		return OK;
152 	}
153 	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'L') &&
154 	         (susp_length > 5) && (susp_version >= 1)) {
155 		/* Symbolic link target. Multiple entries may be used to
156 		   concatenate the complete path target. */
157 		parse_susp_rock_ridge_sl(dir, buffer + 5, susp_length - 5);
158 
159 		return OK;
160 	}
161 	else if ((susp_signature[0] == 'N') && (susp_signature[1] == 'M') &&
162 	         (susp_length > 5) && (susp_version >= 1)) {
163 		/* Alternate POSIX name. Multiple entries may be used to
164 		   concatenate the complete filename. */
165 		rrii_name_current_size = strlen(dir->file_id_rrip);
166 		rrii_name_append_size = susp_length - 5;
167 
168 		/* Concatenate only if name component fits. */
169 		if (rrii_name_current_size + rrii_name_append_size + 1 <
170 		    ISO9660_RRIP_MAX_FILE_ID_LEN) {
171 			strlcpy(dir->file_id_rrip + rrii_name_current_size,
172 			    buffer + 5, rrii_name_append_size+1);
173 		}
174 
175 		return OK;
176 	}
177 	else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L')) {
178 		/* Ignored, skip. */
179 		return OK;
180 	}
181 	else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L')) {
182 		/* Ignored, skip. */
183 		return OK;
184 	}
185 	else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) {
186 		/* Ignored, skip. */
187 		return OK;
188 	}
189 	else if ((susp_signature[0] == 'T') && (susp_signature[1] == 'F') &&
190 	         (susp_length >= 5) && (susp_version >= 1)) {
191 		/* POSIX timestamp. */
192 		rrii_tf_flags = buffer[5];
193 		rrii_tf_offset = 5;
194 
195 		/*
196 		 * ISO 9660 17-byte time format.
197 		 * FIXME: 17-byte time format not supported in TF entry.
198 		 */
199 		if (rrii_tf_flags & (1 << 7)) { }
200 
201 		/* ISO 9660 7-byte time format. */
202 		else {
203 			/* Creation time  */
204 			if ((rrii_tf_flags & (1 << 0)) &&
205 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
206 				memcpy(dir->birthtime, buffer+rrii_tf_offset,
207 				       ISO9660_SIZE_DATE7);
208 				rrii_tf_offset += ISO9660_SIZE_DATE7;
209 			}
210 
211 			/* Modification time */
212 			if ((rrii_tf_flags & (1 << 1)) &&
213 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
214 				memcpy(dir->mtime, buffer+rrii_tf_offset,
215 				       ISO9660_SIZE_DATE7);
216 				rrii_tf_offset += ISO9660_SIZE_DATE7;
217 			}
218 
219 			/* Last access time. */
220 			if ((rrii_tf_flags & (1 << 2)) &&
221 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
222 				memcpy(dir->atime, buffer+rrii_tf_offset,
223 				       ISO9660_SIZE_DATE7);
224 				rrii_tf_offset += ISO9660_SIZE_DATE7;
225 			}
226 
227 			/* Last attribute change time. */
228 			if ((rrii_tf_flags & (1 << 3)) &&
229 			    (rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
230 				memcpy(dir->ctime, buffer+rrii_tf_offset,
231 				       ISO9660_SIZE_DATE7);
232 				rrii_tf_offset += ISO9660_SIZE_DATE7;
233 			}
234 
235 			/* The rest is ignored. */
236 		}
237 
238 		return OK;
239 	}
240 	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'F')) {
241 		/* Ignored, skip. */
242 		return OK;
243 	}
244 
245 	/* Not a Rock Ridge entry. */
246 	return EINVAL;
247 }
248 
249