| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/fs/isofs/rock.c | |||
| 3 | * | |||
| 4 | * (C) 1992, 1993 Eric Youngdale | |||
| 5 | * | |||
| 6 | * Rock Ridge Extensions to iso9660 | |||
| 7 | */ | |||
| 8 | ||||
| 9 | #include <linux/slab.h> | |||
| 10 | #include <linux/pagemap.h> | |||
| 11 | #include <linux/smp_lock.h> | |||
| 12 | ||||
| 13 | #include "isofs.h" | |||
| 14 | #include "rock.h" | |||
| 15 | ||||
| 16 | /* | |||
| 17 | * These functions are designed to read the system areas of a directory record | |||
| 18 | * and extract relevant information. There are different functions provided | |||
| 19 | * depending upon what information we need at the time. One function fills | |||
| 20 | * out an inode structure, a second one extracts a filename, a third one | |||
| 21 | * returns a symbolic link name, and a fourth one returns the extent number | |||
| 22 | * for the file. | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ | |||
| 26 | ||||
| 27 | struct rock_state { | |||
| 28 | void *buffer; | |||
| 29 | unsigned char *chr; | |||
| 30 | int len; | |||
| 31 | int cont_size; | |||
| 32 | int cont_extent; | |||
| 33 | int cont_offset; | |||
| 34 | struct inode *inode; | |||
| 35 | }; | |||
| 36 | ||||
| 37 | /* | |||
| 38 | * This is a way of ensuring that we have something in the system | |||
| 39 | * use fields that is compatible with Rock Ridge. Return zero on success. | |||
| 40 | */ | |||
| 41 | ||||
| 0 | 0 | - | 42 | static int check_sp(struct rock_ridge *rr, struct inode *inode) |
| 43 | { | |||
| 0 | 0 | - | 44 | if (rr->u.SP.magic[0] != 0xbe) |
| 0 | - | 45 | return -1; | |
| 0 | 0 | - | 46 | if (rr->u.SP.magic[1] != 0xef) |
| 0 | - | 47 | return -1; | |
| 48 | ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip; | |||
| 0 | - | 49 | return 0; | |
| 50 | } | |||
| 51 | ||||
| 0 | 0 | - | 52 | static void setup_rock_ridge(struct iso_directory_record *de, |
| 53 | struct inode *inode, struct rock_state *rs) | |||
| 54 | { | |||
| 55 | rs->len = sizeof(struct iso_directory_record) + de->name_len[0]; | |||
| 0 | 0 | - | 56 | if (rs->len & 1) |
| 57 | (rs->len)++; | |||
| 58 | rs->chr = (unsigned char *)de + rs->len; | |||
| 59 | rs->len = *((unsigned char *)de) - rs->len; | |||
| 0 | 0 | - | 60 | if (rs->len < 0) |
| 61 | rs->len = 0; | |||
| 62 | ||||
| 0 | 0 | - | 63 | if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { |
| 64 | rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset; | |||
| 65 | rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset; | |||
| 0 | 0 | - | 66 | if (rs->len < 0) |
| 67 | rs->len = 0; | |||
| 68 | } | |||
| 69 | } | |||
| 70 | ||||
| 0 | 0 | - | 71 | static void init_rock_state(struct rock_state *rs, struct inode *inode) |
| 72 | { | |||
| 73 | memset(rs, 0, sizeof(*rs)); | |||
| 74 | rs->inode = inode; | |||
| 75 | } | |||
| 76 | ||||
| 77 | /* | |||
| 78 | * Returns 0 if the caller should continue scanning, 1 if the scan must end | |||
| 79 | * and -ve on error. | |||
| 80 | */ | |||
| 0 | 0 | - | 81 | static int rock_continue(struct rock_state *rs) |
| 82 | { | |||
| 83 | int ret = 1; | |||
| 84 | int blocksize = 1 << rs->inode->i_blkbits; | |||
| 85 | const int min_de_size = offsetof(struct rock_ridge, u); | |||
| 86 | ||||
| 87 | kfree(rs->buffer); | |||
| 88 | rs->buffer = NULL; | |||
| 89 | ||||
| 90 | if ((unsigned)rs->cont_offset > blocksize - min_de_size || | |||
| 91 | (unsigned)rs->cont_size > blocksize || | |||
| 0 | 0 | - | 92 | (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) { |
| 0 | - | 92 | T || _ || _ | |
| 0 | - | 92 | F || T || _ | |
| 0 | - | 92 | F || F || T | |
| 0 | - | 92 | F || F || F | |
| 93 | printk(KERN_NOTICE "rock: corrupted directory entry. " | |||
| 94 | "extent=%d, offset=%d, size=%d\n", | |||
| 95 | rs->cont_extent, rs->cont_offset, rs->cont_size); | |||
| 96 | ret = -EIO; | |||
| 0 | - | 97 | goto out; | |
| 98 | } | |||
| 99 | ||||
| 0 | 0 | - | 100 | if (rs->cont_extent) { |
| 101 | struct buffer_head *bh; | |||
| 102 | ||||
| 103 | rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL); | |||
| 0 | 0 | - | 104 | if (!rs->buffer) { |
| 105 | ret = -ENOMEM; | |||
| 0 | - | 106 | goto out; | |
| 107 | } | |||
| 108 | ret = -EIO; | |||
| 109 | bh = sb_bread(rs->inode->i_sb, rs->cont_extent); | |||
| 0 | 0 | - | 110 | if (bh) { |
| 111 | memcpy(rs->buffer, bh->b_data + rs->cont_offset, | |||
| 112 | rs->cont_size); | |||
| 113 | put_bh(bh); | |||
| 114 | rs->chr = rs->buffer; | |||
| 115 | rs->len = rs->cont_size; | |||
| 116 | rs->cont_extent = 0; | |||
| 117 | rs->cont_size = 0; | |||
| 118 | rs->cont_offset = 0; | |||
| 0 | - | 119 | return 0; | |
| 120 | } | |||
| 121 | printk("Unable to read rock-ridge attributes\n"); | |||
| 122 | } | |||
| 123 | out: | |||
| 124 | kfree(rs->buffer); | |||
| 125 | rs->buffer = NULL; | |||
| 0 | - | 126 | return ret; | |
| 127 | } | |||
| 128 | ||||
| 129 | /* | |||
| 130 | * We think there's a record of type `sig' at rs->chr. Parse the signature | |||
| 131 | * and make sure that there's really room for a record of that type. | |||
| 132 | */ | |||
| 0 | 0 | - | 133 | static int rock_check_overflow(struct rock_state *rs, int sig) |
| 134 | { | |||
| 135 | int len; | |||
| 136 | ||||
| 137 | switch (sig) { | |||
| 0 | - | 138 | case SIG('S', 'P'): | |
| 139 | len = sizeof(struct SU_SP_s); | |||
| 0 | - | 140 | break; | |
| 0 | - | 141 | case SIG('C', 'E'): | |
| 142 | len = sizeof(struct SU_CE_s); | |||
| 0 | - | 143 | break; | |
| 0 | - | 144 | case SIG('E', 'R'): | |
| 145 | len = sizeof(struct SU_ER_s); | |||
| 0 | - | 146 | break; | |
| 0 | - | 147 | case SIG('R', 'R'): | |
| 148 | len = sizeof(struct RR_RR_s); | |||
| 0 | - | 149 | break; | |
| 0 | - | 150 | case SIG('P', 'X'): | |
| 151 | len = sizeof(struct RR_PX_s); | |||
| 0 | - | 152 | break; | |
| 0 | - | 153 | case SIG('P', 'N'): | |
| 154 | len = sizeof(struct RR_PN_s); | |||
| 0 | - | 155 | break; | |
| 0 | - | 156 | case SIG('S', 'L'): | |
| 157 | len = sizeof(struct RR_SL_s); | |||
| 0 | - | 158 | break; | |
| 0 | - | 159 | case SIG('N', 'M'): | |
| 160 | len = sizeof(struct RR_NM_s); | |||
| 0 | - | 161 | break; | |
| 0 | - | 162 | case SIG('C', 'L'): | |
| 163 | len = sizeof(struct RR_CL_s); | |||
| 0 | - | 164 | break; | |
| 0 | - | 165 | case SIG('P', 'L'): | |
| 166 | len = sizeof(struct RR_PL_s); | |||
| 0 | - | 167 | break; | |
| 0 | - | 168 | case SIG('T', 'F'): | |
| 169 | len = sizeof(struct RR_TF_s); | |||
| 0 | - | 170 | break; | |
| 0 | - | 171 | case SIG('Z', 'F'): | |
| 172 | len = sizeof(struct RR_ZF_s); | |||
| 0 | - | 173 | break; | |
| 0 | - | 174 | default: | |
| 175 | len = 0; | |||
| 0 | - | 176 | break; | |
| 177 | } | |||
| 178 | len += offsetof(struct rock_ridge, u); | |||
| 0 | 0 | - | 179 | if (len > rs->len) { |
| 180 | printk(KERN_NOTICE "rock: directory entry would overflow " | |||
| 181 | "storage\n"); | |||
| 182 | printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n", | |||
| 183 | sig, len, rs->len); | |||
| 0 | - | 184 | return -EIO; | |
| 185 | } | |||
| 0 | - | 186 | return 0; | |
| 187 | } | |||
| 188 | ||||
| 189 | /* | |||
| 190 | * return length of name field; 0: not found, -1: to be ignored | |||
| 191 | */ | |||
| 0 | 0 | - | 192 | int get_rock_ridge_filename(struct iso_directory_record *de, |
| 193 | char *retname, struct inode *inode) | |||
| 194 | { | |||
| 195 | struct rock_state rs; | |||
| 196 | struct rock_ridge *rr; | |||
| 197 | int sig; | |||
| 198 | int retnamlen = 0; | |||
| 199 | int truncate = 0; | |||
| 200 | int ret = 0; | |||
| 201 | ||||
| 0 | 0 | - | 202 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
| 0 | - | 203 | return 0; | |
| 204 | *retname = 0; | |||
| 205 | ||||
| 206 | init_rock_state(&rs, inode); | |||
| 207 | setup_rock_ridge(de, inode, &rs); | |||
| 208 | repeat: | |||
| 209 | ||||
| 0 | 0 | - | 210 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
| 211 | rr = (struct rock_ridge *)rs.chr; | |||
| 0 | 0 | - | 212 | if (rr->len < 3) |
| 0 | - | 213 | goto out; /* Something got screwed up here */ | |
| 214 | sig = isonum_721(rs.chr); | |||
| 0 | 0 | - | 215 | if (rock_check_overflow(&rs, sig)) |
| 0 | - | 216 | goto eio; | |
| 217 | rs.chr += rr->len; | |||
| 218 | rs.len -= rr->len; | |||
| 0 | 0 | - | 219 | if (rs.len < 0) |
| 0 | - | 220 | goto eio; /* corrupted isofs */ | |
| 221 | ||||
| 222 | switch (sig) { | |||
| 0 | - | 223 | case SIG('R', 'R'): | |
| 0 | 0 | - | 224 | if ((rr->u.RR.flags[0] & RR_NM) == 0) |
| 0 | - | 225 | goto out; | |
| 0 | - | 226 | break; | |
| 0 | - | 227 | case SIG('S', 'P'): | |
| 0 | 0 | - | 228 | if (check_sp(rr, inode)) |
| 0 | - | 229 | goto out; | |
| 0 | - | 230 | break; | |
| 0 | - | 231 | case SIG('C', 'E'): | |
| 232 | rs.cont_extent = isonum_733(rr->u.CE.extent); | |||
| 233 | rs.cont_offset = isonum_733(rr->u.CE.offset); | |||
| 234 | rs.cont_size = isonum_733(rr->u.CE.size); | |||
| 0 | - | 235 | break; | |
| 0 | - | 236 | case SIG('N', 'M'): | |
| 0 | 0 | - | 237 | if (truncate) |
| 0 | - | 238 | break; | |
| 0 | 0 | - | 239 | if (rr->len < 5) |
| 0 | - | 240 | break; | |
| 241 | /* | |||
| 242 | * If the flags are 2 or 4, this indicates '.' or '..'. | |||
| 243 | * We don't want to do anything with this, because it | |||
| 244 | * screws up the code that calls us. We don't really | |||
| 245 | * care anyways, since we can just use the non-RR | |||
| 246 | * name. | |||
| 247 | */ | |||
| 0 | 0 | - | 248 | if (rr->u.NM.flags & 6) |
| 0 | - | 249 | break; | |
| 250 | ||||
| 0 | 0 | - | 251 | if (rr->u.NM.flags & ~1) { |
| 252 | printk("Unsupported NM flag settings (%d)\n", | |||
| 253 | rr->u.NM.flags); | |||
| 0 | - | 254 | break; | |
| 255 | } | |||
| 0 | 0 | - | 256 | if ((strlen(retname) + rr->len - 5) >= 254) { |
| 257 | truncate = 1; | |||
| 0 | - | 258 | break; | |
| 259 | } | |||
| 260 | strncat(retname, rr->u.NM.name, rr->len - 5); | |||
| 261 | retnamlen += rr->len - 5; | |||
| 0 | - | 262 | break; | |
| 0 | - | 263 | case SIG('R', 'E'): | |
| 264 | kfree(rs.buffer); | |||
| 0 | - | 265 | return -1; | |
| 0 | - | 266 | default: | |
| 0 | - | 267 | break; | |
| 268 | } | |||
| 269 | } | |||
| 270 | ret = rock_continue(&rs); | |||
| 0 | 0 | - | 271 | if (ret == 0) |
| 0 | - | 272 | goto repeat; | |
| 0 | 0 | - | 273 | if (ret == 1) |
| 0 | - | 274 | return retnamlen; /* If 0, this file did not have a NM field */ | |
| 275 | out: | |||
| 276 | kfree(rs.buffer); | |||
| 0 | - | 277 | return ret; | |
| 278 | eio: | |||
| 279 | ret = -EIO; | |||
| 0 | - | 280 | goto out; | |
| 281 | } | |||
| 282 | ||||
| 283 | static int | |||
| 0 | 0 | - | 284 | parse_rock_ridge_inode_internal(struct iso_directory_record *de, |
| 285 | struct inode *inode, int regard_xa) | |||
| 286 | { | |||
| 287 | int symlink_len = 0; | |||
| 288 | int cnt, sig; | |||
| 289 | struct inode *reloc; | |||
| 290 | struct rock_ridge *rr; | |||
| 291 | int rootflag; | |||
| 292 | struct rock_state rs; | |||
| 293 | int ret = 0; | |||
| 294 | ||||
| 0 | 0 | - | 295 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
| 0 | - | 296 | return 0; | |
| 297 | ||||
| 298 | init_rock_state(&rs, inode); | |||
| 299 | setup_rock_ridge(de, inode, &rs); | |||
| 0 | 0 | - | 300 | if (regard_xa) { |
| 301 | rs.chr += 14; | |||
| 302 | rs.len -= 14; | |||
| 0 | 0 | - | 303 | if (rs.len < 0) |
| 304 | rs.len = 0; | |||
| 305 | } | |||
| 306 | ||||
| 307 | repeat: | |||
| 0 | 0 | - | 308 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
| 309 | rr = (struct rock_ridge *)rs.chr; | |||
| 0 | 0 | - | 310 | if (rr->len < 3) |
| 0 | - | 311 | goto out; /* Something got screwed up here */ | |
| 312 | sig = isonum_721(rs.chr); | |||
| 0 | 0 | - | 313 | if (rock_check_overflow(&rs, sig)) |
| 0 | - | 314 | goto eio; | |
| 315 | rs.chr += rr->len; | |||
| 316 | rs.len -= rr->len; | |||
| 0 | 0 | - | 317 | if (rs.len < 0) |
| 0 | - | 318 | goto eio; /* corrupted isofs */ | |
| 319 | ||||
| 320 | switch (sig) { | |||
| 321 | #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ | |||
| 322 | case SIG('R', 'R'): | |||
| 323 | if ((rr->u.RR.flags[0] & | |||
| 324 | (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) | |||
| 325 | goto out; | |||
| 326 | break; | |||
| 327 | #endif | |||
| 0 | - | 328 | case SIG('S', 'P'): | |
| 0 | 0 | - | 329 | if (check_sp(rr, inode)) |
| 0 | - | 330 | goto out; | |
| 0 | - | 331 | break; | |
| 0 | - | 332 | case SIG('C', 'E'): | |
| 333 | rs.cont_extent = isonum_733(rr->u.CE.extent); | |||
| 334 | rs.cont_offset = isonum_733(rr->u.CE.offset); | |||
| 335 | rs.cont_size = isonum_733(rr->u.CE.size); | |||
| 0 | - | 336 | break; | |
| 0 | - | 337 | case SIG('E', 'R'): | |
| 338 | ISOFS_SB(inode->i_sb)->s_rock = 1; | |||
| 339 | printk(KERN_DEBUG "ISO 9660 Extensions: "); | |||
| 340 | { | |||
| 341 | int p; | |||
| 0 | 0 | - | 342 | for (p = 0; p < rr->u.ER.len_id; p++) |
| 343 | printk("%c", rr->u.ER.data[p]); | |||
| 344 | } | |||
| 345 | printk("\n"); | |||
| 0 | - | 346 | break; | |
| 0 | - | 347 | case SIG('P', 'X'): | |
| 348 | inode->i_mode = isonum_733(rr->u.PX.mode); | |||
| 349 | inode->i_nlink = isonum_733(rr->u.PX.n_links); | |||
| 350 | inode->i_uid = isonum_733(rr->u.PX.uid); | |||
| 351 | inode->i_gid = isonum_733(rr->u.PX.gid); | |||
| 0 | - | 352 | break; | |
| 0 | - | 353 | case SIG('P', 'N'): | |
| 354 | { | |||
| 355 | int high, low; | |||
| 356 | high = isonum_733(rr->u.PN.dev_high); | |||
| 357 | low = isonum_733(rr->u.PN.dev_low); | |||
| 358 | /* | |||
| 359 | * The Rock Ridge standard specifies that if | |||
| 360 | * sizeof(dev_t) <= 4, then the high field is | |||
| 361 | * unused, and the device number is completely | |||
| 362 | * stored in the low field. Some writers may | |||
| 363 | * ignore this subtlety, | |||
| 364 | * and as a result we test to see if the entire | |||
| 365 | * device number is | |||
| 366 | * stored in the low field, and use that. | |||
| 367 | */ | |||
| 0 | 0 | - | 368 | if ((low & ~0xff) && high == 0) { |
| 0 | - | 368 | (T) && T | |
| 0 | - | 368 | (T) && F | |
| 0 | - | 368 | (F) && _ | |
| 369 | inode->i_rdev = | |||
| 370 | MKDEV(low >> 8, low & 0xff); | |||
| 371 | } else { | |||
| 372 | inode->i_rdev = | |||
| 373 | MKDEV(high, low); | |||
| 374 | } | |||
| 375 | } | |||
| 0 | - | 376 | break; | |
| 0 | - | 377 | case SIG('T', 'F'): | |
| 378 | /* | |||
| 379 | * Some RRIP writers incorrectly place ctime in the | |||
| 380 | * TF_CREATE field. Try to handle this correctly for | |||
| 381 | * either case. | |||
| 382 | */ | |||
| 383 | /* Rock ridge never appears on a High Sierra disk */ | |||
| 384 | cnt = 0; | |||
| 0 | 0 | - | 385 | if (rr->u.TF.flags & TF_CREATE) { |
| 386 | inode->i_ctime.tv_sec = | |||
| 387 | iso_date(rr->u.TF.times[cnt++].time, | |||
| 388 | 0); | |||
| 389 | inode->i_ctime.tv_nsec = 0; | |||
| 390 | } | |||
| 0 | 0 | - | 391 | if (rr->u.TF.flags & TF_MODIFY) { |
| 392 | inode->i_mtime.tv_sec = | |||
| 393 | iso_date(rr->u.TF.times[cnt++].time, | |||
| 394 | 0); | |||
| 395 | inode->i_mtime.tv_nsec = 0; | |||
| 396 | } | |||
| 0 | 0 | - | 397 | if (rr->u.TF.flags & TF_ACCESS) { |
| 398 | inode->i_atime.tv_sec = | |||
| 399 | iso_date(rr->u.TF.times[cnt++].time, | |||
| 400 | 0); | |||
| 401 | inode->i_atime.tv_nsec = 0; | |||
| 402 | } | |||
| 0 | 0 | - | 403 | if (rr->u.TF.flags & TF_ATTRIBUTES) { |
| 404 | inode->i_ctime.tv_sec = | |||
| 405 | iso_date(rr->u.TF.times[cnt++].time, | |||
| 406 | 0); | |||
| 407 | inode->i_ctime.tv_nsec = 0; | |||
| 408 | } | |||
| 0 | - | 409 | break; | |
| 0 | - | 410 | case SIG('S', 'L'): | |
| 411 | { | |||
| 412 | int slen; | |||
| 413 | struct SL_component *slp; | |||
| 414 | struct SL_component *oldslp; | |||
| 415 | slen = rr->len - 5; | |||
| 416 | slp = &rr->u.SL.link; | |||
| 417 | inode->i_size = symlink_len; | |||
| 0 | 0 | - | 418 | while (slen > 1) { |
| 419 | rootflag = 0; | |||
| 420 | switch (slp->flags & ~1) { | |||
| 0 | - | 421 | case 0: | |
| 422 | inode->i_size += | |||
| 423 | slp->len; | |||
| 0 | - | 424 | break; | |
| 0 | - | 425 | case 2: | |
| 426 | inode->i_size += 1; | |||
| 0 | - | 427 | break; | |
| 0 | - | 428 | case 4: | |
| 429 | inode->i_size += 2; | |||
| 0 | - | 430 | break; | |
| 0 | - | 431 | case 8: | |
| 432 | rootflag = 1; | |||
| 433 | inode->i_size += 1; | |||
| 0 | - | 434 | break; | |
| 0 | - | 435 | default: | |
| 436 | printk("Symlink component flag " | |||
| 437 | "not implemented\n"); | |||
| 438 | } | |||
| 439 | slen -= slp->len + 2; | |||
| 440 | oldslp = slp; | |||
| 441 | slp = (struct SL_component *) | |||
| 442 | (((char *)slp) + slp->len + 2); | |||
| 443 | ||||
| 0 | 0 | - | 444 | if (slen < 2) { |
| 445 | if (((rr->u.SL. | |||
| 446 | flags & 1) != 0) | |||
| 447 | && | |||
| 448 | ((oldslp-> | |||
| 0 | 0 | - | 449 | flags & 1) == 0)) |
| 0 | - | 449 | (T) && (T) | |
| 0 | - | 449 | (T) && (F) | |
| 0 | - | 449 | (F) && (_) | |
| 450 | inode->i_size += | |||
| 451 | 1; | |||
| 0 | - | 452 | break; | |
| 453 | } | |||
| 454 | ||||
| 455 | /* | |||
| 456 | * If this component record isn't | |||
| 457 | * continued, then append a '/'. | |||
| 458 | */ | |||
| 459 | if (!rootflag | |||
| 0 | 0 | - | 460 | && (oldslp->flags & 1) == 0) |
| 0 | - | 460 | T && T | |
| 0 | - | 460 | T && F | |
| 0 | - | 460 | F && _ | |
| 461 | inode->i_size += 1; | |||
| 462 | } | |||
| 463 | } | |||
| 464 | symlink_len = inode->i_size; | |||
| 0 | - | 465 | break; | |