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