18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/isofs/rock.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) 1992, 1993 Eric Youngdale 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Rock Ridge Extensions to iso9660 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "isofs.h" 148c2ecf20Sopenharmony_ci#include "rock.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * These functions are designed to read the system areas of a directory record 188c2ecf20Sopenharmony_ci * and extract relevant information. There are different functions provided 198c2ecf20Sopenharmony_ci * depending upon what information we need at the time. One function fills 208c2ecf20Sopenharmony_ci * out an inode structure, a second one extracts a filename, a third one 218c2ecf20Sopenharmony_ci * returns a symbolic link name, and a fourth one returns the extent number 228c2ecf20Sopenharmony_ci * for the file. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct rock_state { 288c2ecf20Sopenharmony_ci void *buffer; 298c2ecf20Sopenharmony_ci unsigned char *chr; 308c2ecf20Sopenharmony_ci int len; 318c2ecf20Sopenharmony_ci int cont_size; 328c2ecf20Sopenharmony_ci int cont_extent; 338c2ecf20Sopenharmony_ci int cont_offset; 348c2ecf20Sopenharmony_ci int cont_loops; 358c2ecf20Sopenharmony_ci struct inode *inode; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * This is a way of ensuring that we have something in the system 408c2ecf20Sopenharmony_ci * use fields that is compatible with Rock Ridge. Return zero on success. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int check_sp(struct rock_ridge *rr, struct inode *inode) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (rr->u.SP.magic[0] != 0xbe) 468c2ecf20Sopenharmony_ci return -1; 478c2ecf20Sopenharmony_ci if (rr->u.SP.magic[1] != 0xef) 488c2ecf20Sopenharmony_ci return -1; 498c2ecf20Sopenharmony_ci ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip; 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void setup_rock_ridge(struct iso_directory_record *de, 548c2ecf20Sopenharmony_ci struct inode *inode, struct rock_state *rs) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci rs->len = sizeof(struct iso_directory_record) + de->name_len[0]; 578c2ecf20Sopenharmony_ci if (rs->len & 1) 588c2ecf20Sopenharmony_ci (rs->len)++; 598c2ecf20Sopenharmony_ci rs->chr = (unsigned char *)de + rs->len; 608c2ecf20Sopenharmony_ci rs->len = *((unsigned char *)de) - rs->len; 618c2ecf20Sopenharmony_ci if (rs->len < 0) 628c2ecf20Sopenharmony_ci rs->len = 0; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { 658c2ecf20Sopenharmony_ci rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset; 668c2ecf20Sopenharmony_ci rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset; 678c2ecf20Sopenharmony_ci if (rs->len < 0) 688c2ecf20Sopenharmony_ci rs->len = 0; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void init_rock_state(struct rock_state *rs, struct inode *inode) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci memset(rs, 0, sizeof(*rs)); 758c2ecf20Sopenharmony_ci rs->inode = inode; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Maximum number of Rock Ridge continuation entries */ 798c2ecf20Sopenharmony_ci#define RR_MAX_CE_ENTRIES 32 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * Returns 0 if the caller should continue scanning, 1 if the scan must end 838c2ecf20Sopenharmony_ci * and -ve on error. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic int rock_continue(struct rock_state *rs) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci int ret = 1; 888c2ecf20Sopenharmony_ci int blocksize = 1 << rs->inode->i_blkbits; 898c2ecf20Sopenharmony_ci const int min_de_size = offsetof(struct rock_ridge, u); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci kfree(rs->buffer); 928c2ecf20Sopenharmony_ci rs->buffer = NULL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if ((unsigned)rs->cont_offset > blocksize - min_de_size || 958c2ecf20Sopenharmony_ci (unsigned)rs->cont_size > blocksize || 968c2ecf20Sopenharmony_ci (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) { 978c2ecf20Sopenharmony_ci printk(KERN_NOTICE "rock: corrupted directory entry. " 988c2ecf20Sopenharmony_ci "extent=%d, offset=%d, size=%d\n", 998c2ecf20Sopenharmony_ci rs->cont_extent, rs->cont_offset, rs->cont_size); 1008c2ecf20Sopenharmony_ci ret = -EIO; 1018c2ecf20Sopenharmony_ci goto out; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (rs->cont_extent) { 1058c2ecf20Sopenharmony_ci struct buffer_head *bh; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL); 1088c2ecf20Sopenharmony_ci if (!rs->buffer) { 1098c2ecf20Sopenharmony_ci ret = -ENOMEM; 1108c2ecf20Sopenharmony_ci goto out; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci ret = -EIO; 1138c2ecf20Sopenharmony_ci if (++rs->cont_loops >= RR_MAX_CE_ENTRIES) 1148c2ecf20Sopenharmony_ci goto out; 1158c2ecf20Sopenharmony_ci bh = sb_bread(rs->inode->i_sb, rs->cont_extent); 1168c2ecf20Sopenharmony_ci if (bh) { 1178c2ecf20Sopenharmony_ci memcpy(rs->buffer, bh->b_data + rs->cont_offset, 1188c2ecf20Sopenharmony_ci rs->cont_size); 1198c2ecf20Sopenharmony_ci put_bh(bh); 1208c2ecf20Sopenharmony_ci rs->chr = rs->buffer; 1218c2ecf20Sopenharmony_ci rs->len = rs->cont_size; 1228c2ecf20Sopenharmony_ci rs->cont_extent = 0; 1238c2ecf20Sopenharmony_ci rs->cont_size = 0; 1248c2ecf20Sopenharmony_ci rs->cont_offset = 0; 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci printk("Unable to read rock-ridge attributes\n"); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ciout: 1308c2ecf20Sopenharmony_ci kfree(rs->buffer); 1318c2ecf20Sopenharmony_ci rs->buffer = NULL; 1328c2ecf20Sopenharmony_ci return ret; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* 1368c2ecf20Sopenharmony_ci * We think there's a record of type `sig' at rs->chr. Parse the signature 1378c2ecf20Sopenharmony_ci * and make sure that there's really room for a record of that type. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_cistatic int rock_check_overflow(struct rock_state *rs, int sig) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int len; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci switch (sig) { 1448c2ecf20Sopenharmony_ci case SIG('S', 'P'): 1458c2ecf20Sopenharmony_ci len = sizeof(struct SU_SP_s); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case SIG('C', 'E'): 1488c2ecf20Sopenharmony_ci len = sizeof(struct SU_CE_s); 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case SIG('E', 'R'): 1518c2ecf20Sopenharmony_ci len = sizeof(struct SU_ER_s); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case SIG('R', 'R'): 1548c2ecf20Sopenharmony_ci len = sizeof(struct RR_RR_s); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case SIG('P', 'X'): 1578c2ecf20Sopenharmony_ci len = sizeof(struct RR_PX_s); 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case SIG('P', 'N'): 1608c2ecf20Sopenharmony_ci len = sizeof(struct RR_PN_s); 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci case SIG('S', 'L'): 1638c2ecf20Sopenharmony_ci len = sizeof(struct RR_SL_s); 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case SIG('N', 'M'): 1668c2ecf20Sopenharmony_ci len = sizeof(struct RR_NM_s); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case SIG('C', 'L'): 1698c2ecf20Sopenharmony_ci len = sizeof(struct RR_CL_s); 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case SIG('P', 'L'): 1728c2ecf20Sopenharmony_ci len = sizeof(struct RR_PL_s); 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case SIG('T', 'F'): 1758c2ecf20Sopenharmony_ci len = sizeof(struct RR_TF_s); 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case SIG('Z', 'F'): 1788c2ecf20Sopenharmony_ci len = sizeof(struct RR_ZF_s); 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci default: 1818c2ecf20Sopenharmony_ci len = 0; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci len += offsetof(struct rock_ridge, u); 1858c2ecf20Sopenharmony_ci if (len > rs->len) { 1868c2ecf20Sopenharmony_ci printk(KERN_NOTICE "rock: directory entry would overflow " 1878c2ecf20Sopenharmony_ci "storage\n"); 1888c2ecf20Sopenharmony_ci printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n", 1898c2ecf20Sopenharmony_ci sig, len, rs->len); 1908c2ecf20Sopenharmony_ci return -EIO; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* 1968c2ecf20Sopenharmony_ci * return length of name field; 0: not found, -1: to be ignored 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ciint get_rock_ridge_filename(struct iso_directory_record *de, 1998c2ecf20Sopenharmony_ci char *retname, struct inode *inode) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct rock_state rs; 2028c2ecf20Sopenharmony_ci struct rock_ridge *rr; 2038c2ecf20Sopenharmony_ci int sig; 2048c2ecf20Sopenharmony_ci int retnamlen = 0; 2058c2ecf20Sopenharmony_ci int truncate = 0; 2068c2ecf20Sopenharmony_ci int ret = 0; 2078c2ecf20Sopenharmony_ci char *p; 2088c2ecf20Sopenharmony_ci int len; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!ISOFS_SB(inode->i_sb)->s_rock) 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci *retname = 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci init_rock_state(&rs, inode); 2158c2ecf20Sopenharmony_ci setup_rock_ridge(de, inode, &rs); 2168c2ecf20Sopenharmony_cirepeat: 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci while (rs.len > 2) { /* There may be one byte for padding somewhere */ 2198c2ecf20Sopenharmony_ci rr = (struct rock_ridge *)rs.chr; 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * Ignore rock ridge info if rr->len is out of range, but 2228c2ecf20Sopenharmony_ci * don't return -EIO because that would make the file 2238c2ecf20Sopenharmony_ci * invisible. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci if (rr->len < 3) 2268c2ecf20Sopenharmony_ci goto out; /* Something got screwed up here */ 2278c2ecf20Sopenharmony_ci sig = isonum_721(rs.chr); 2288c2ecf20Sopenharmony_ci if (rock_check_overflow(&rs, sig)) 2298c2ecf20Sopenharmony_ci goto eio; 2308c2ecf20Sopenharmony_ci rs.chr += rr->len; 2318c2ecf20Sopenharmony_ci rs.len -= rr->len; 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * As above, just ignore the rock ridge info if rr->len 2348c2ecf20Sopenharmony_ci * is bogus. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci if (rs.len < 0) 2378c2ecf20Sopenharmony_ci goto out; /* Something got screwed up here */ 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci switch (sig) { 2408c2ecf20Sopenharmony_ci case SIG('R', 'R'): 2418c2ecf20Sopenharmony_ci if ((rr->u.RR.flags[0] & RR_NM) == 0) 2428c2ecf20Sopenharmony_ci goto out; 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case SIG('S', 'P'): 2458c2ecf20Sopenharmony_ci if (check_sp(rr, inode)) 2468c2ecf20Sopenharmony_ci goto out; 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci case SIG('C', 'E'): 2498c2ecf20Sopenharmony_ci rs.cont_extent = isonum_733(rr->u.CE.extent); 2508c2ecf20Sopenharmony_ci rs.cont_offset = isonum_733(rr->u.CE.offset); 2518c2ecf20Sopenharmony_ci rs.cont_size = isonum_733(rr->u.CE.size); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case SIG('N', 'M'): 2548c2ecf20Sopenharmony_ci if (truncate) 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci if (rr->len < 5) 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * If the flags are 2 or 4, this indicates '.' or '..'. 2608c2ecf20Sopenharmony_ci * We don't want to do anything with this, because it 2618c2ecf20Sopenharmony_ci * screws up the code that calls us. We don't really 2628c2ecf20Sopenharmony_ci * care anyways, since we can just use the non-RR 2638c2ecf20Sopenharmony_ci * name. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci if (rr->u.NM.flags & 6) 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (rr->u.NM.flags & ~1) { 2698c2ecf20Sopenharmony_ci printk("Unsupported NM flag settings (%d)\n", 2708c2ecf20Sopenharmony_ci rr->u.NM.flags); 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci len = rr->len - 5; 2748c2ecf20Sopenharmony_ci if (retnamlen + len >= 254) { 2758c2ecf20Sopenharmony_ci truncate = 1; 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci p = memchr(rr->u.NM.name, '\0', len); 2798c2ecf20Sopenharmony_ci if (unlikely(p)) 2808c2ecf20Sopenharmony_ci len = p - rr->u.NM.name; 2818c2ecf20Sopenharmony_ci memcpy(retname + retnamlen, rr->u.NM.name, len); 2828c2ecf20Sopenharmony_ci retnamlen += len; 2838c2ecf20Sopenharmony_ci retname[retnamlen] = '\0'; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case SIG('R', 'E'): 2868c2ecf20Sopenharmony_ci kfree(rs.buffer); 2878c2ecf20Sopenharmony_ci return -1; 2888c2ecf20Sopenharmony_ci default: 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci ret = rock_continue(&rs); 2938c2ecf20Sopenharmony_ci if (ret == 0) 2948c2ecf20Sopenharmony_ci goto repeat; 2958c2ecf20Sopenharmony_ci if (ret == 1) 2968c2ecf20Sopenharmony_ci return retnamlen; /* If 0, this file did not have a NM field */ 2978c2ecf20Sopenharmony_ciout: 2988c2ecf20Sopenharmony_ci kfree(rs.buffer); 2998c2ecf20Sopenharmony_ci return ret; 3008c2ecf20Sopenharmony_cieio: 3018c2ecf20Sopenharmony_ci ret = -EIO; 3028c2ecf20Sopenharmony_ci goto out; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci#define RR_REGARD_XA 1 3068c2ecf20Sopenharmony_ci#define RR_RELOC_DE 2 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int 3098c2ecf20Sopenharmony_ciparse_rock_ridge_inode_internal(struct iso_directory_record *de, 3108c2ecf20Sopenharmony_ci struct inode *inode, int flags) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci int symlink_len = 0; 3138c2ecf20Sopenharmony_ci int cnt, sig; 3148c2ecf20Sopenharmony_ci unsigned int reloc_block; 3158c2ecf20Sopenharmony_ci struct inode *reloc; 3168c2ecf20Sopenharmony_ci struct rock_ridge *rr; 3178c2ecf20Sopenharmony_ci int rootflag; 3188c2ecf20Sopenharmony_ci struct rock_state rs; 3198c2ecf20Sopenharmony_ci int ret = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!ISOFS_SB(inode->i_sb)->s_rock) 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci init_rock_state(&rs, inode); 3258c2ecf20Sopenharmony_ci setup_rock_ridge(de, inode, &rs); 3268c2ecf20Sopenharmony_ci if (flags & RR_REGARD_XA) { 3278c2ecf20Sopenharmony_ci rs.chr += 14; 3288c2ecf20Sopenharmony_ci rs.len -= 14; 3298c2ecf20Sopenharmony_ci if (rs.len < 0) 3308c2ecf20Sopenharmony_ci rs.len = 0; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cirepeat: 3348c2ecf20Sopenharmony_ci while (rs.len > 2) { /* There may be one byte for padding somewhere */ 3358c2ecf20Sopenharmony_ci rr = (struct rock_ridge *)rs.chr; 3368c2ecf20Sopenharmony_ci /* 3378c2ecf20Sopenharmony_ci * Ignore rock ridge info if rr->len is out of range, but 3388c2ecf20Sopenharmony_ci * don't return -EIO because that would make the file 3398c2ecf20Sopenharmony_ci * invisible. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci if (rr->len < 3) 3428c2ecf20Sopenharmony_ci goto out; /* Something got screwed up here */ 3438c2ecf20Sopenharmony_ci sig = isonum_721(rs.chr); 3448c2ecf20Sopenharmony_ci if (rock_check_overflow(&rs, sig)) 3458c2ecf20Sopenharmony_ci goto eio; 3468c2ecf20Sopenharmony_ci rs.chr += rr->len; 3478c2ecf20Sopenharmony_ci rs.len -= rr->len; 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * As above, just ignore the rock ridge info if rr->len 3508c2ecf20Sopenharmony_ci * is bogus. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci if (rs.len < 0) 3538c2ecf20Sopenharmony_ci goto out; /* Something got screwed up here */ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci switch (sig) { 3568c2ecf20Sopenharmony_ci#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ 3578c2ecf20Sopenharmony_ci case SIG('R', 'R'): 3588c2ecf20Sopenharmony_ci if ((rr->u.RR.flags[0] & 3598c2ecf20Sopenharmony_ci (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) 3608c2ecf20Sopenharmony_ci goto out; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci#endif 3638c2ecf20Sopenharmony_ci case SIG('S', 'P'): 3648c2ecf20Sopenharmony_ci if (check_sp(rr, inode)) 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci break; 3678c2ecf20Sopenharmony_ci case SIG('C', 'E'): 3688c2ecf20Sopenharmony_ci rs.cont_extent = isonum_733(rr->u.CE.extent); 3698c2ecf20Sopenharmony_ci rs.cont_offset = isonum_733(rr->u.CE.offset); 3708c2ecf20Sopenharmony_ci rs.cont_size = isonum_733(rr->u.CE.size); 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case SIG('E', 'R'): 3738c2ecf20Sopenharmony_ci /* Invalid length of ER tag id? */ 3748c2ecf20Sopenharmony_ci if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len) 3758c2ecf20Sopenharmony_ci goto out; 3768c2ecf20Sopenharmony_ci ISOFS_SB(inode->i_sb)->s_rock = 1; 3778c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ISO 9660 Extensions: "); 3788c2ecf20Sopenharmony_ci { 3798c2ecf20Sopenharmony_ci int p; 3808c2ecf20Sopenharmony_ci for (p = 0; p < rr->u.ER.len_id; p++) 3818c2ecf20Sopenharmony_ci printk(KERN_CONT "%c", rr->u.ER.data[p]); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case SIG('P', 'X'): 3868c2ecf20Sopenharmony_ci inode->i_mode = isonum_733(rr->u.PX.mode); 3878c2ecf20Sopenharmony_ci set_nlink(inode, isonum_733(rr->u.PX.n_links)); 3888c2ecf20Sopenharmony_ci i_uid_write(inode, isonum_733(rr->u.PX.uid)); 3898c2ecf20Sopenharmony_ci i_gid_write(inode, isonum_733(rr->u.PX.gid)); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case SIG('P', 'N'): 3928c2ecf20Sopenharmony_ci { 3938c2ecf20Sopenharmony_ci int high, low; 3948c2ecf20Sopenharmony_ci high = isonum_733(rr->u.PN.dev_high); 3958c2ecf20Sopenharmony_ci low = isonum_733(rr->u.PN.dev_low); 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci * The Rock Ridge standard specifies that if 3988c2ecf20Sopenharmony_ci * sizeof(dev_t) <= 4, then the high field is 3998c2ecf20Sopenharmony_ci * unused, and the device number is completely 4008c2ecf20Sopenharmony_ci * stored in the low field. Some writers may 4018c2ecf20Sopenharmony_ci * ignore this subtlety, 4028c2ecf20Sopenharmony_ci * and as a result we test to see if the entire 4038c2ecf20Sopenharmony_ci * device number is 4048c2ecf20Sopenharmony_ci * stored in the low field, and use that. 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci if ((low & ~0xff) && high == 0) { 4078c2ecf20Sopenharmony_ci inode->i_rdev = 4088c2ecf20Sopenharmony_ci MKDEV(low >> 8, low & 0xff); 4098c2ecf20Sopenharmony_ci } else { 4108c2ecf20Sopenharmony_ci inode->i_rdev = 4118c2ecf20Sopenharmony_ci MKDEV(high, low); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci case SIG('T', 'F'): 4168c2ecf20Sopenharmony_ci /* 4178c2ecf20Sopenharmony_ci * Some RRIP writers incorrectly place ctime in the 4188c2ecf20Sopenharmony_ci * TF_CREATE field. Try to handle this correctly for 4198c2ecf20Sopenharmony_ci * either case. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci /* Rock ridge never appears on a High Sierra disk */ 4228c2ecf20Sopenharmony_ci cnt = 0; 4238c2ecf20Sopenharmony_ci if (rr->u.TF.flags & TF_CREATE) { 4248c2ecf20Sopenharmony_ci inode->i_ctime.tv_sec = 4258c2ecf20Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 4268c2ecf20Sopenharmony_ci 0); 4278c2ecf20Sopenharmony_ci inode->i_ctime.tv_nsec = 0; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci if (rr->u.TF.flags & TF_MODIFY) { 4308c2ecf20Sopenharmony_ci inode->i_mtime.tv_sec = 4318c2ecf20Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 4328c2ecf20Sopenharmony_ci 0); 4338c2ecf20Sopenharmony_ci inode->i_mtime.tv_nsec = 0; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci if (rr->u.TF.flags & TF_ACCESS) { 4368c2ecf20Sopenharmony_ci inode->i_atime.tv_sec = 4378c2ecf20Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 4388c2ecf20Sopenharmony_ci 0); 4398c2ecf20Sopenharmony_ci inode->i_atime.tv_nsec = 0; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci if (rr->u.TF.flags & TF_ATTRIBUTES) { 4428c2ecf20Sopenharmony_ci inode->i_ctime.tv_sec = 4438c2ecf20Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 4448c2ecf20Sopenharmony_ci 0); 4458c2ecf20Sopenharmony_ci inode->i_ctime.tv_nsec = 0; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci case SIG('S', 'L'): 4498c2ecf20Sopenharmony_ci { 4508c2ecf20Sopenharmony_ci int slen; 4518c2ecf20Sopenharmony_ci struct SL_component *slp; 4528c2ecf20Sopenharmony_ci struct SL_component *oldslp; 4538c2ecf20Sopenharmony_ci slen = rr->len - 5; 4548c2ecf20Sopenharmony_ci slp = &rr->u.SL.link; 4558c2ecf20Sopenharmony_ci inode->i_size = symlink_len; 4568c2ecf20Sopenharmony_ci while (slen > 1) { 4578c2ecf20Sopenharmony_ci rootflag = 0; 4588c2ecf20Sopenharmony_ci switch (slp->flags & ~1) { 4598c2ecf20Sopenharmony_ci case 0: 4608c2ecf20Sopenharmony_ci inode->i_size += 4618c2ecf20Sopenharmony_ci slp->len; 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci case 2: 4648c2ecf20Sopenharmony_ci inode->i_size += 1; 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci case 4: 4678c2ecf20Sopenharmony_ci inode->i_size += 2; 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci case 8: 4708c2ecf20Sopenharmony_ci rootflag = 1; 4718c2ecf20Sopenharmony_ci inode->i_size += 1; 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci default: 4748c2ecf20Sopenharmony_ci printk("Symlink component flag " 4758c2ecf20Sopenharmony_ci "not implemented\n"); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci slen -= slp->len + 2; 4788c2ecf20Sopenharmony_ci oldslp = slp; 4798c2ecf20Sopenharmony_ci slp = (struct SL_component *) 4808c2ecf20Sopenharmony_ci (((char *)slp) + slp->len + 2); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (slen < 2) { 4838c2ecf20Sopenharmony_ci if (((rr->u.SL. 4848c2ecf20Sopenharmony_ci flags & 1) != 0) 4858c2ecf20Sopenharmony_ci && 4868c2ecf20Sopenharmony_ci ((oldslp-> 4878c2ecf20Sopenharmony_ci flags & 1) == 0)) 4888c2ecf20Sopenharmony_ci inode->i_size += 4898c2ecf20Sopenharmony_ci 1; 4908c2ecf20Sopenharmony_ci break; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * If this component record isn't 4958c2ecf20Sopenharmony_ci * continued, then append a '/'. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci if (!rootflag 4988c2ecf20Sopenharmony_ci && (oldslp->flags & 1) == 0) 4998c2ecf20Sopenharmony_ci inode->i_size += 1; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci symlink_len = inode->i_size; 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case SIG('R', 'E'): 5058c2ecf20Sopenharmony_ci printk(KERN_WARNING "Attempt to read inode for " 5068c2ecf20Sopenharmony_ci "relocated directory\n"); 5078c2ecf20Sopenharmony_ci goto out; 5088c2ecf20Sopenharmony_ci case SIG('C', 'L'): 5098c2ecf20Sopenharmony_ci if (flags & RR_RELOC_DE) { 5108c2ecf20Sopenharmony_ci printk(KERN_ERR 5118c2ecf20Sopenharmony_ci "ISOFS: Recursive directory relocation " 5128c2ecf20Sopenharmony_ci "is not supported\n"); 5138c2ecf20Sopenharmony_ci goto eio; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci reloc_block = isonum_733(rr->u.CL.location); 5168c2ecf20Sopenharmony_ci if (reloc_block == ISOFS_I(inode)->i_iget5_block && 5178c2ecf20Sopenharmony_ci ISOFS_I(inode)->i_iget5_offset == 0) { 5188c2ecf20Sopenharmony_ci printk(KERN_ERR 5198c2ecf20Sopenharmony_ci "ISOFS: Directory relocation points to " 5208c2ecf20Sopenharmony_ci "itself\n"); 5218c2ecf20Sopenharmony_ci goto eio; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci ISOFS_I(inode)->i_first_extent = reloc_block; 5248c2ecf20Sopenharmony_ci reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0); 5258c2ecf20Sopenharmony_ci if (IS_ERR(reloc)) { 5268c2ecf20Sopenharmony_ci ret = PTR_ERR(reloc); 5278c2ecf20Sopenharmony_ci goto out; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci inode->i_mode = reloc->i_mode; 5308c2ecf20Sopenharmony_ci set_nlink(inode, reloc->i_nlink); 5318c2ecf20Sopenharmony_ci inode->i_uid = reloc->i_uid; 5328c2ecf20Sopenharmony_ci inode->i_gid = reloc->i_gid; 5338c2ecf20Sopenharmony_ci inode->i_rdev = reloc->i_rdev; 5348c2ecf20Sopenharmony_ci inode->i_size = reloc->i_size; 5358c2ecf20Sopenharmony_ci inode->i_blocks = reloc->i_blocks; 5368c2ecf20Sopenharmony_ci inode->i_atime = reloc->i_atime; 5378c2ecf20Sopenharmony_ci inode->i_ctime = reloc->i_ctime; 5388c2ecf20Sopenharmony_ci inode->i_mtime = reloc->i_mtime; 5398c2ecf20Sopenharmony_ci iput(reloc); 5408c2ecf20Sopenharmony_ci break; 5418c2ecf20Sopenharmony_ci#ifdef CONFIG_ZISOFS 5428c2ecf20Sopenharmony_ci case SIG('Z', 'F'): { 5438c2ecf20Sopenharmony_ci int algo; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (ISOFS_SB(inode->i_sb)->s_nocompress) 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci algo = isonum_721(rr->u.ZF.algorithm); 5488c2ecf20Sopenharmony_ci if (algo == SIG('p', 'z')) { 5498c2ecf20Sopenharmony_ci int block_shift = 5508c2ecf20Sopenharmony_ci isonum_711(&rr->u.ZF.parms[1]); 5518c2ecf20Sopenharmony_ci if (block_shift > 17) { 5528c2ecf20Sopenharmony_ci printk(KERN_WARNING "isofs: " 5538c2ecf20Sopenharmony_ci "Can't handle ZF block " 5548c2ecf20Sopenharmony_ci "size of 2^%d\n", 5558c2ecf20Sopenharmony_ci block_shift); 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci /* 5588c2ecf20Sopenharmony_ci * Note: we don't change 5598c2ecf20Sopenharmony_ci * i_blocks here 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci ISOFS_I(inode)->i_file_format = 5628c2ecf20Sopenharmony_ci isofs_file_compressed; 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * Parameters to compression 5658c2ecf20Sopenharmony_ci * algorithm (header size, 5668c2ecf20Sopenharmony_ci * block size) 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci ISOFS_I(inode)->i_format_parm[0] = 5698c2ecf20Sopenharmony_ci isonum_711(&rr->u.ZF.parms[0]); 5708c2ecf20Sopenharmony_ci ISOFS_I(inode)->i_format_parm[1] = 5718c2ecf20Sopenharmony_ci isonum_711(&rr->u.ZF.parms[1]); 5728c2ecf20Sopenharmony_ci inode->i_size = 5738c2ecf20Sopenharmony_ci isonum_733(rr->u.ZF. 5748c2ecf20Sopenharmony_ci real_size); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci printk(KERN_WARNING 5788c2ecf20Sopenharmony_ci "isofs: Unknown ZF compression " 5798c2ecf20Sopenharmony_ci "algorithm: %c%c\n", 5808c2ecf20Sopenharmony_ci rr->u.ZF.algorithm[0], 5818c2ecf20Sopenharmony_ci rr->u.ZF.algorithm[1]); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci#endif 5868c2ecf20Sopenharmony_ci default: 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci ret = rock_continue(&rs); 5918c2ecf20Sopenharmony_ci if (ret == 0) 5928c2ecf20Sopenharmony_ci goto repeat; 5938c2ecf20Sopenharmony_ci if (ret == 1) 5948c2ecf20Sopenharmony_ci ret = 0; 5958c2ecf20Sopenharmony_ciout: 5968c2ecf20Sopenharmony_ci kfree(rs.buffer); 5978c2ecf20Sopenharmony_ci return ret; 5988c2ecf20Sopenharmony_cieio: 5998c2ecf20Sopenharmony_ci ret = -EIO; 6008c2ecf20Sopenharmony_ci goto out; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int slen; 6068c2ecf20Sopenharmony_ci int rootflag; 6078c2ecf20Sopenharmony_ci struct SL_component *oldslp; 6088c2ecf20Sopenharmony_ci struct SL_component *slp; 6098c2ecf20Sopenharmony_ci slen = rr->len - 5; 6108c2ecf20Sopenharmony_ci slp = &rr->u.SL.link; 6118c2ecf20Sopenharmony_ci while (slen > 1) { 6128c2ecf20Sopenharmony_ci rootflag = 0; 6138c2ecf20Sopenharmony_ci switch (slp->flags & ~1) { 6148c2ecf20Sopenharmony_ci case 0: 6158c2ecf20Sopenharmony_ci if (slp->len > plimit - rpnt) 6168c2ecf20Sopenharmony_ci return NULL; 6178c2ecf20Sopenharmony_ci memcpy(rpnt, slp->text, slp->len); 6188c2ecf20Sopenharmony_ci rpnt += slp->len; 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci case 2: 6218c2ecf20Sopenharmony_ci if (rpnt >= plimit) 6228c2ecf20Sopenharmony_ci return NULL; 6238c2ecf20Sopenharmony_ci *rpnt++ = '.'; 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci case 4: 6268c2ecf20Sopenharmony_ci if (2 > plimit - rpnt) 6278c2ecf20Sopenharmony_ci return NULL; 6288c2ecf20Sopenharmony_ci *rpnt++ = '.'; 6298c2ecf20Sopenharmony_ci *rpnt++ = '.'; 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci case 8: 6328c2ecf20Sopenharmony_ci if (rpnt >= plimit) 6338c2ecf20Sopenharmony_ci return NULL; 6348c2ecf20Sopenharmony_ci rootflag = 1; 6358c2ecf20Sopenharmony_ci *rpnt++ = '/'; 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci default: 6388c2ecf20Sopenharmony_ci printk("Symlink component flag not implemented (%d)\n", 6398c2ecf20Sopenharmony_ci slp->flags); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci slen -= slp->len + 2; 6428c2ecf20Sopenharmony_ci oldslp = slp; 6438c2ecf20Sopenharmony_ci slp = (struct SL_component *)((char *)slp + slp->len + 2); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (slen < 2) { 6468c2ecf20Sopenharmony_ci /* 6478c2ecf20Sopenharmony_ci * If there is another SL record, and this component 6488c2ecf20Sopenharmony_ci * record isn't continued, then add a slash. 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_ci if ((!rootflag) && (rr->u.SL.flags & 1) && 6518c2ecf20Sopenharmony_ci !(oldslp->flags & 1)) { 6528c2ecf20Sopenharmony_ci if (rpnt >= plimit) 6538c2ecf20Sopenharmony_ci return NULL; 6548c2ecf20Sopenharmony_ci *rpnt++ = '/'; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* 6608c2ecf20Sopenharmony_ci * If this component record isn't continued, then append a '/'. 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_ci if (!rootflag && !(oldslp->flags & 1)) { 6638c2ecf20Sopenharmony_ci if (rpnt >= plimit) 6648c2ecf20Sopenharmony_ci return NULL; 6658c2ecf20Sopenharmony_ci *rpnt++ = '/'; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci return rpnt; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ciint parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode, 6728c2ecf20Sopenharmony_ci int relocated) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci int flags = relocated ? RR_RELOC_DE : 0; 6758c2ecf20Sopenharmony_ci int result = parse_rock_ridge_inode_internal(de, inode, flags); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* 6788c2ecf20Sopenharmony_ci * if rockridge flag was reset and we didn't look for attributes 6798c2ecf20Sopenharmony_ci * behind eventual XA attributes, have a look there 6808c2ecf20Sopenharmony_ci */ 6818c2ecf20Sopenharmony_ci if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) 6828c2ecf20Sopenharmony_ci && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { 6838c2ecf20Sopenharmony_ci result = parse_rock_ridge_inode_internal(de, inode, 6848c2ecf20Sopenharmony_ci flags | RR_REGARD_XA); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci return result; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/* 6908c2ecf20Sopenharmony_ci * readpage() for symlinks: reads symlink contents into the page and either 6918c2ecf20Sopenharmony_ci * makes it uptodate and returns 0 or returns error (-EIO) 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_cistatic int rock_ridge_symlink_readpage(struct file *file, struct page *page) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 6968c2ecf20Sopenharmony_ci struct iso_inode_info *ei = ISOFS_I(inode); 6978c2ecf20Sopenharmony_ci struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); 6988c2ecf20Sopenharmony_ci char *link = page_address(page); 6998c2ecf20Sopenharmony_ci unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 7008c2ecf20Sopenharmony_ci struct buffer_head *bh; 7018c2ecf20Sopenharmony_ci char *rpnt = link; 7028c2ecf20Sopenharmony_ci unsigned char *pnt; 7038c2ecf20Sopenharmony_ci struct iso_directory_record *raw_de; 7048c2ecf20Sopenharmony_ci unsigned long block, offset; 7058c2ecf20Sopenharmony_ci int sig; 7068c2ecf20Sopenharmony_ci struct rock_ridge *rr; 7078c2ecf20Sopenharmony_ci struct rock_state rs; 7088c2ecf20Sopenharmony_ci int ret; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (!sbi->s_rock) 7118c2ecf20Sopenharmony_ci goto error; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci init_rock_state(&rs, inode); 7148c2ecf20Sopenharmony_ci block = ei->i_iget5_block; 7158c2ecf20Sopenharmony_ci bh = sb_bread(inode->i_sb, block); 7168c2ecf20Sopenharmony_ci if (!bh) 7178c2ecf20Sopenharmony_ci goto out_noread; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci offset = ei->i_iget5_offset; 7208c2ecf20Sopenharmony_ci pnt = (unsigned char *)bh->b_data + offset; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci raw_de = (struct iso_directory_record *)pnt; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* 7258c2ecf20Sopenharmony_ci * If we go past the end of the buffer, there is some sort of error. 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci if (offset + *pnt > bufsize) 7288c2ecf20Sopenharmony_ci goto out_bad_span; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * Now test for possible Rock Ridge extensions which will override 7328c2ecf20Sopenharmony_ci * some of these numbers in the inode structure. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci setup_rock_ridge(raw_de, inode, &rs); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cirepeat: 7388c2ecf20Sopenharmony_ci while (rs.len > 2) { /* There may be one byte for padding somewhere */ 7398c2ecf20Sopenharmony_ci rr = (struct rock_ridge *)rs.chr; 7408c2ecf20Sopenharmony_ci if (rr->len < 3) 7418c2ecf20Sopenharmony_ci goto out; /* Something got screwed up here */ 7428c2ecf20Sopenharmony_ci sig = isonum_721(rs.chr); 7438c2ecf20Sopenharmony_ci if (rock_check_overflow(&rs, sig)) 7448c2ecf20Sopenharmony_ci goto out; 7458c2ecf20Sopenharmony_ci rs.chr += rr->len; 7468c2ecf20Sopenharmony_ci rs.len -= rr->len; 7478c2ecf20Sopenharmony_ci if (rs.len < 0) 7488c2ecf20Sopenharmony_ci goto out; /* corrupted isofs */ 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci switch (sig) { 7518c2ecf20Sopenharmony_ci case SIG('R', 'R'): 7528c2ecf20Sopenharmony_ci if ((rr->u.RR.flags[0] & RR_SL) == 0) 7538c2ecf20Sopenharmony_ci goto out; 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci case SIG('S', 'P'): 7568c2ecf20Sopenharmony_ci if (check_sp(rr, inode)) 7578c2ecf20Sopenharmony_ci goto out; 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci case SIG('S', 'L'): 7608c2ecf20Sopenharmony_ci rpnt = get_symlink_chunk(rpnt, rr, 7618c2ecf20Sopenharmony_ci link + (PAGE_SIZE - 1)); 7628c2ecf20Sopenharmony_ci if (rpnt == NULL) 7638c2ecf20Sopenharmony_ci goto out; 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci case SIG('C', 'E'): 7668c2ecf20Sopenharmony_ci /* This tells is if there is a continuation record */ 7678c2ecf20Sopenharmony_ci rs.cont_extent = isonum_733(rr->u.CE.extent); 7688c2ecf20Sopenharmony_ci rs.cont_offset = isonum_733(rr->u.CE.offset); 7698c2ecf20Sopenharmony_ci rs.cont_size = isonum_733(rr->u.CE.size); 7708c2ecf20Sopenharmony_ci default: 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci ret = rock_continue(&rs); 7758c2ecf20Sopenharmony_ci if (ret == 0) 7768c2ecf20Sopenharmony_ci goto repeat; 7778c2ecf20Sopenharmony_ci if (ret < 0) 7788c2ecf20Sopenharmony_ci goto fail; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (rpnt == link) 7818c2ecf20Sopenharmony_ci goto fail; 7828c2ecf20Sopenharmony_ci brelse(bh); 7838c2ecf20Sopenharmony_ci *rpnt = '\0'; 7848c2ecf20Sopenharmony_ci SetPageUptodate(page); 7858c2ecf20Sopenharmony_ci unlock_page(page); 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* error exit from macro */ 7898c2ecf20Sopenharmony_ciout: 7908c2ecf20Sopenharmony_ci kfree(rs.buffer); 7918c2ecf20Sopenharmony_ci goto fail; 7928c2ecf20Sopenharmony_ciout_noread: 7938c2ecf20Sopenharmony_ci printk("unable to read i-node block"); 7948c2ecf20Sopenharmony_ci goto fail; 7958c2ecf20Sopenharmony_ciout_bad_span: 7968c2ecf20Sopenharmony_ci printk("symlink spans iso9660 blocks\n"); 7978c2ecf20Sopenharmony_cifail: 7988c2ecf20Sopenharmony_ci brelse(bh); 7998c2ecf20Sopenharmony_cierror: 8008c2ecf20Sopenharmony_ci SetPageError(page); 8018c2ecf20Sopenharmony_ci unlock_page(page); 8028c2ecf20Sopenharmony_ci return -EIO; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ciconst struct address_space_operations isofs_symlink_aops = { 8068c2ecf20Sopenharmony_ci .readpage = rock_ridge_symlink_readpage 8078c2ecf20Sopenharmony_ci}; 808