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