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