162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/isofs/rock.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) 1992, 1993 Eric Youngdale 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Rock Ridge Extensions to iso9660 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/pagemap.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "isofs.h" 1462306a36Sopenharmony_ci#include "rock.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * These functions are designed to read the system areas of a directory record 1862306a36Sopenharmony_ci * and extract relevant information. There are different functions provided 1962306a36Sopenharmony_ci * depending upon what information we need at the time. One function fills 2062306a36Sopenharmony_ci * out an inode structure, a second one extracts a filename, a third one 2162306a36Sopenharmony_ci * returns a symbolic link name, and a fourth one returns the extent number 2262306a36Sopenharmony_ci * for the file. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct rock_state { 2862306a36Sopenharmony_ci void *buffer; 2962306a36Sopenharmony_ci unsigned char *chr; 3062306a36Sopenharmony_ci int len; 3162306a36Sopenharmony_ci int cont_size; 3262306a36Sopenharmony_ci int cont_extent; 3362306a36Sopenharmony_ci int cont_offset; 3462306a36Sopenharmony_ci int cont_loops; 3562306a36Sopenharmony_ci struct inode *inode; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * This is a way of ensuring that we have something in the system 4062306a36Sopenharmony_ci * use fields that is compatible with Rock Ridge. Return zero on success. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int check_sp(struct rock_ridge *rr, struct inode *inode) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci if (rr->u.SP.magic[0] != 0xbe) 4662306a36Sopenharmony_ci return -1; 4762306a36Sopenharmony_ci if (rr->u.SP.magic[1] != 0xef) 4862306a36Sopenharmony_ci return -1; 4962306a36Sopenharmony_ci ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip; 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void setup_rock_ridge(struct iso_directory_record *de, 5462306a36Sopenharmony_ci struct inode *inode, struct rock_state *rs) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci rs->len = sizeof(struct iso_directory_record) + de->name_len[0]; 5762306a36Sopenharmony_ci if (rs->len & 1) 5862306a36Sopenharmony_ci (rs->len)++; 5962306a36Sopenharmony_ci rs->chr = (unsigned char *)de + rs->len; 6062306a36Sopenharmony_ci rs->len = *((unsigned char *)de) - rs->len; 6162306a36Sopenharmony_ci if (rs->len < 0) 6262306a36Sopenharmony_ci rs->len = 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { 6562306a36Sopenharmony_ci rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset; 6662306a36Sopenharmony_ci rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset; 6762306a36Sopenharmony_ci if (rs->len < 0) 6862306a36Sopenharmony_ci rs->len = 0; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void init_rock_state(struct rock_state *rs, struct inode *inode) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci memset(rs, 0, sizeof(*rs)); 7562306a36Sopenharmony_ci rs->inode = inode; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Maximum number of Rock Ridge continuation entries */ 7962306a36Sopenharmony_ci#define RR_MAX_CE_ENTRIES 32 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Returns 0 if the caller should continue scanning, 1 if the scan must end 8362306a36Sopenharmony_ci * and -ve on error. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_cistatic int rock_continue(struct rock_state *rs) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci int ret = 1; 8862306a36Sopenharmony_ci int blocksize = 1 << rs->inode->i_blkbits; 8962306a36Sopenharmony_ci const int min_de_size = offsetof(struct rock_ridge, u); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci kfree(rs->buffer); 9262306a36Sopenharmony_ci rs->buffer = NULL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if ((unsigned)rs->cont_offset > blocksize - min_de_size || 9562306a36Sopenharmony_ci (unsigned)rs->cont_size > blocksize || 9662306a36Sopenharmony_ci (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) { 9762306a36Sopenharmony_ci printk(KERN_NOTICE "rock: corrupted directory entry. " 9862306a36Sopenharmony_ci "extent=%d, offset=%d, size=%d\n", 9962306a36Sopenharmony_ci rs->cont_extent, rs->cont_offset, rs->cont_size); 10062306a36Sopenharmony_ci ret = -EIO; 10162306a36Sopenharmony_ci goto out; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (rs->cont_extent) { 10562306a36Sopenharmony_ci struct buffer_head *bh; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL); 10862306a36Sopenharmony_ci if (!rs->buffer) { 10962306a36Sopenharmony_ci ret = -ENOMEM; 11062306a36Sopenharmony_ci goto out; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci ret = -EIO; 11362306a36Sopenharmony_ci if (++rs->cont_loops >= RR_MAX_CE_ENTRIES) 11462306a36Sopenharmony_ci goto out; 11562306a36Sopenharmony_ci bh = sb_bread(rs->inode->i_sb, rs->cont_extent); 11662306a36Sopenharmony_ci if (bh) { 11762306a36Sopenharmony_ci memcpy(rs->buffer, bh->b_data + rs->cont_offset, 11862306a36Sopenharmony_ci rs->cont_size); 11962306a36Sopenharmony_ci put_bh(bh); 12062306a36Sopenharmony_ci rs->chr = rs->buffer; 12162306a36Sopenharmony_ci rs->len = rs->cont_size; 12262306a36Sopenharmony_ci rs->cont_extent = 0; 12362306a36Sopenharmony_ci rs->cont_size = 0; 12462306a36Sopenharmony_ci rs->cont_offset = 0; 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci printk("Unable to read rock-ridge attributes\n"); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ciout: 13062306a36Sopenharmony_ci kfree(rs->buffer); 13162306a36Sopenharmony_ci rs->buffer = NULL; 13262306a36Sopenharmony_ci return ret; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * We think there's a record of type `sig' at rs->chr. Parse the signature 13762306a36Sopenharmony_ci * and make sure that there's really room for a record of that type. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_cistatic int rock_check_overflow(struct rock_state *rs, int sig) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int len; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci switch (sig) { 14462306a36Sopenharmony_ci case SIG('S', 'P'): 14562306a36Sopenharmony_ci len = sizeof(struct SU_SP_s); 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case SIG('C', 'E'): 14862306a36Sopenharmony_ci len = sizeof(struct SU_CE_s); 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case SIG('E', 'R'): 15162306a36Sopenharmony_ci len = sizeof(struct SU_ER_s); 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case SIG('R', 'R'): 15462306a36Sopenharmony_ci len = sizeof(struct RR_RR_s); 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci case SIG('P', 'X'): 15762306a36Sopenharmony_ci len = sizeof(struct RR_PX_s); 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci case SIG('P', 'N'): 16062306a36Sopenharmony_ci len = sizeof(struct RR_PN_s); 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci case SIG('S', 'L'): 16362306a36Sopenharmony_ci len = sizeof(struct RR_SL_s); 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case SIG('N', 'M'): 16662306a36Sopenharmony_ci len = sizeof(struct RR_NM_s); 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci case SIG('C', 'L'): 16962306a36Sopenharmony_ci len = sizeof(struct RR_CL_s); 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci case SIG('P', 'L'): 17262306a36Sopenharmony_ci len = sizeof(struct RR_PL_s); 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci case SIG('T', 'F'): 17562306a36Sopenharmony_ci len = sizeof(struct RR_TF_s); 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case SIG('Z', 'F'): 17862306a36Sopenharmony_ci len = sizeof(struct RR_ZF_s); 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci default: 18162306a36Sopenharmony_ci len = 0; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci len += offsetof(struct rock_ridge, u); 18562306a36Sopenharmony_ci if (len > rs->len) { 18662306a36Sopenharmony_ci printk(KERN_NOTICE "rock: directory entry would overflow " 18762306a36Sopenharmony_ci "storage\n"); 18862306a36Sopenharmony_ci printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n", 18962306a36Sopenharmony_ci sig, len, rs->len); 19062306a36Sopenharmony_ci return -EIO; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* 19662306a36Sopenharmony_ci * return length of name field; 0: not found, -1: to be ignored 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ciint get_rock_ridge_filename(struct iso_directory_record *de, 19962306a36Sopenharmony_ci char *retname, struct inode *inode) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct rock_state rs; 20262306a36Sopenharmony_ci struct rock_ridge *rr; 20362306a36Sopenharmony_ci int sig; 20462306a36Sopenharmony_ci int retnamlen = 0; 20562306a36Sopenharmony_ci int truncate = 0; 20662306a36Sopenharmony_ci int ret = 0; 20762306a36Sopenharmony_ci char *p; 20862306a36Sopenharmony_ci int len; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (!ISOFS_SB(inode->i_sb)->s_rock) 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci *retname = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci init_rock_state(&rs, inode); 21562306a36Sopenharmony_ci setup_rock_ridge(de, inode, &rs); 21662306a36Sopenharmony_cirepeat: 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci while (rs.len > 2) { /* There may be one byte for padding somewhere */ 21962306a36Sopenharmony_ci rr = (struct rock_ridge *)rs.chr; 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Ignore rock ridge info if rr->len is out of range, but 22262306a36Sopenharmony_ci * don't return -EIO because that would make the file 22362306a36Sopenharmony_ci * invisible. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci if (rr->len < 3) 22662306a36Sopenharmony_ci goto out; /* Something got screwed up here */ 22762306a36Sopenharmony_ci sig = isonum_721(rs.chr); 22862306a36Sopenharmony_ci if (rock_check_overflow(&rs, sig)) 22962306a36Sopenharmony_ci goto eio; 23062306a36Sopenharmony_ci rs.chr += rr->len; 23162306a36Sopenharmony_ci rs.len -= rr->len; 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * As above, just ignore the rock ridge info if rr->len 23462306a36Sopenharmony_ci * is bogus. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci if (rs.len < 0) 23762306a36Sopenharmony_ci goto out; /* Something got screwed up here */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci switch (sig) { 24062306a36Sopenharmony_ci case SIG('R', 'R'): 24162306a36Sopenharmony_ci if ((rr->u.RR.flags[0] & RR_NM) == 0) 24262306a36Sopenharmony_ci goto out; 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci case SIG('S', 'P'): 24562306a36Sopenharmony_ci if (check_sp(rr, inode)) 24662306a36Sopenharmony_ci goto out; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case SIG('C', 'E'): 24962306a36Sopenharmony_ci rs.cont_extent = isonum_733(rr->u.CE.extent); 25062306a36Sopenharmony_ci rs.cont_offset = isonum_733(rr->u.CE.offset); 25162306a36Sopenharmony_ci rs.cont_size = isonum_733(rr->u.CE.size); 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case SIG('N', 'M'): 25462306a36Sopenharmony_ci if (truncate) 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci if (rr->len < 5) 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * If the flags are 2 or 4, this indicates '.' or '..'. 26062306a36Sopenharmony_ci * We don't want to do anything with this, because it 26162306a36Sopenharmony_ci * screws up the code that calls us. We don't really 26262306a36Sopenharmony_ci * care anyways, since we can just use the non-RR 26362306a36Sopenharmony_ci * name. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci if (rr->u.NM.flags & 6) 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (rr->u.NM.flags & ~1) { 26962306a36Sopenharmony_ci printk("Unsupported NM flag settings (%d)\n", 27062306a36Sopenharmony_ci rr->u.NM.flags); 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci len = rr->len - 5; 27462306a36Sopenharmony_ci if (retnamlen + len >= 254) { 27562306a36Sopenharmony_ci truncate = 1; 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci p = memchr(rr->u.NM.name, '\0', len); 27962306a36Sopenharmony_ci if (unlikely(p)) 28062306a36Sopenharmony_ci len = p - rr->u.NM.name; 28162306a36Sopenharmony_ci memcpy(retname + retnamlen, rr->u.NM.name, len); 28262306a36Sopenharmony_ci retnamlen += len; 28362306a36Sopenharmony_ci retname[retnamlen] = '\0'; 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case SIG('R', 'E'): 28662306a36Sopenharmony_ci kfree(rs.buffer); 28762306a36Sopenharmony_ci return -1; 28862306a36Sopenharmony_ci default: 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci ret = rock_continue(&rs); 29362306a36Sopenharmony_ci if (ret == 0) 29462306a36Sopenharmony_ci goto repeat; 29562306a36Sopenharmony_ci if (ret == 1) 29662306a36Sopenharmony_ci return retnamlen; /* If 0, this file did not have a NM field */ 29762306a36Sopenharmony_ciout: 29862306a36Sopenharmony_ci kfree(rs.buffer); 29962306a36Sopenharmony_ci return ret; 30062306a36Sopenharmony_cieio: 30162306a36Sopenharmony_ci ret = -EIO; 30262306a36Sopenharmony_ci goto out; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci#define RR_REGARD_XA 1 30662306a36Sopenharmony_ci#define RR_RELOC_DE 2 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int 30962306a36Sopenharmony_ciparse_rock_ridge_inode_internal(struct iso_directory_record *de, 31062306a36Sopenharmony_ci struct inode *inode, int flags) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int symlink_len = 0; 31362306a36Sopenharmony_ci int cnt, sig; 31462306a36Sopenharmony_ci unsigned int reloc_block; 31562306a36Sopenharmony_ci struct inode *reloc; 31662306a36Sopenharmony_ci struct rock_ridge *rr; 31762306a36Sopenharmony_ci int rootflag; 31862306a36Sopenharmony_ci struct rock_state rs; 31962306a36Sopenharmony_ci int ret = 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (!ISOFS_SB(inode->i_sb)->s_rock) 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci init_rock_state(&rs, inode); 32562306a36Sopenharmony_ci setup_rock_ridge(de, inode, &rs); 32662306a36Sopenharmony_ci if (flags & RR_REGARD_XA) { 32762306a36Sopenharmony_ci rs.chr += 14; 32862306a36Sopenharmony_ci rs.len -= 14; 32962306a36Sopenharmony_ci if (rs.len < 0) 33062306a36Sopenharmony_ci rs.len = 0; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cirepeat: 33462306a36Sopenharmony_ci while (rs.len > 2) { /* There may be one byte for padding somewhere */ 33562306a36Sopenharmony_ci rr = (struct rock_ridge *)rs.chr; 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * Ignore rock ridge info if rr->len is out of range, but 33862306a36Sopenharmony_ci * don't return -EIO because that would make the file 33962306a36Sopenharmony_ci * invisible. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci if (rr->len < 3) 34262306a36Sopenharmony_ci goto out; /* Something got screwed up here */ 34362306a36Sopenharmony_ci sig = isonum_721(rs.chr); 34462306a36Sopenharmony_ci if (rock_check_overflow(&rs, sig)) 34562306a36Sopenharmony_ci goto eio; 34662306a36Sopenharmony_ci rs.chr += rr->len; 34762306a36Sopenharmony_ci rs.len -= rr->len; 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * As above, just ignore the rock ridge info if rr->len 35062306a36Sopenharmony_ci * is bogus. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci if (rs.len < 0) 35362306a36Sopenharmony_ci goto out; /* Something got screwed up here */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci switch (sig) { 35662306a36Sopenharmony_ci#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ 35762306a36Sopenharmony_ci case SIG('R', 'R'): 35862306a36Sopenharmony_ci if ((rr->u.RR.flags[0] & 35962306a36Sopenharmony_ci (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) 36062306a36Sopenharmony_ci goto out; 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci#endif 36362306a36Sopenharmony_ci case SIG('S', 'P'): 36462306a36Sopenharmony_ci if (check_sp(rr, inode)) 36562306a36Sopenharmony_ci goto out; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case SIG('C', 'E'): 36862306a36Sopenharmony_ci rs.cont_extent = isonum_733(rr->u.CE.extent); 36962306a36Sopenharmony_ci rs.cont_offset = isonum_733(rr->u.CE.offset); 37062306a36Sopenharmony_ci rs.cont_size = isonum_733(rr->u.CE.size); 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci case SIG('E', 'R'): 37362306a36Sopenharmony_ci /* Invalid length of ER tag id? */ 37462306a36Sopenharmony_ci if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len) 37562306a36Sopenharmony_ci goto out; 37662306a36Sopenharmony_ci ISOFS_SB(inode->i_sb)->s_rock = 1; 37762306a36Sopenharmony_ci printk(KERN_DEBUG "ISO 9660 Extensions: "); 37862306a36Sopenharmony_ci { 37962306a36Sopenharmony_ci int p; 38062306a36Sopenharmony_ci for (p = 0; p < rr->u.ER.len_id; p++) 38162306a36Sopenharmony_ci printk(KERN_CONT "%c", rr->u.ER.data[p]); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci printk(KERN_CONT "\n"); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case SIG('P', 'X'): 38662306a36Sopenharmony_ci inode->i_mode = isonum_733(rr->u.PX.mode); 38762306a36Sopenharmony_ci set_nlink(inode, isonum_733(rr->u.PX.n_links)); 38862306a36Sopenharmony_ci i_uid_write(inode, isonum_733(rr->u.PX.uid)); 38962306a36Sopenharmony_ci i_gid_write(inode, isonum_733(rr->u.PX.gid)); 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case SIG('P', 'N'): 39262306a36Sopenharmony_ci { 39362306a36Sopenharmony_ci int high, low; 39462306a36Sopenharmony_ci high = isonum_733(rr->u.PN.dev_high); 39562306a36Sopenharmony_ci low = isonum_733(rr->u.PN.dev_low); 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * The Rock Ridge standard specifies that if 39862306a36Sopenharmony_ci * sizeof(dev_t) <= 4, then the high field is 39962306a36Sopenharmony_ci * unused, and the device number is completely 40062306a36Sopenharmony_ci * stored in the low field. Some writers may 40162306a36Sopenharmony_ci * ignore this subtlety, 40262306a36Sopenharmony_ci * and as a result we test to see if the entire 40362306a36Sopenharmony_ci * device number is 40462306a36Sopenharmony_ci * stored in the low field, and use that. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci if ((low & ~0xff) && high == 0) { 40762306a36Sopenharmony_ci inode->i_rdev = 40862306a36Sopenharmony_ci MKDEV(low >> 8, low & 0xff); 40962306a36Sopenharmony_ci } else { 41062306a36Sopenharmony_ci inode->i_rdev = 41162306a36Sopenharmony_ci MKDEV(high, low); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case SIG('T', 'F'): 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * Some RRIP writers incorrectly place ctime in the 41862306a36Sopenharmony_ci * TF_CREATE field. Try to handle this correctly for 41962306a36Sopenharmony_ci * either case. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci /* Rock ridge never appears on a High Sierra disk */ 42262306a36Sopenharmony_ci cnt = 0; 42362306a36Sopenharmony_ci if (rr->u.TF.flags & TF_CREATE) { 42462306a36Sopenharmony_ci inode_set_ctime(inode, 42562306a36Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 0), 42662306a36Sopenharmony_ci 0); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci if (rr->u.TF.flags & TF_MODIFY) { 42962306a36Sopenharmony_ci inode->i_mtime.tv_sec = 43062306a36Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 43162306a36Sopenharmony_ci 0); 43262306a36Sopenharmony_ci inode->i_mtime.tv_nsec = 0; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci if (rr->u.TF.flags & TF_ACCESS) { 43562306a36Sopenharmony_ci inode->i_atime.tv_sec = 43662306a36Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 43762306a36Sopenharmony_ci 0); 43862306a36Sopenharmony_ci inode->i_atime.tv_nsec = 0; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci if (rr->u.TF.flags & TF_ATTRIBUTES) { 44162306a36Sopenharmony_ci inode_set_ctime(inode, 44262306a36Sopenharmony_ci iso_date(rr->u.TF.times[cnt++].time, 0), 44362306a36Sopenharmony_ci 0); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case SIG('S', 'L'): 44762306a36Sopenharmony_ci { 44862306a36Sopenharmony_ci int slen; 44962306a36Sopenharmony_ci struct SL_component *slp; 45062306a36Sopenharmony_ci struct SL_component *oldslp; 45162306a36Sopenharmony_ci slen = rr->len - 5; 45262306a36Sopenharmony_ci slp = &rr->u.SL.link; 45362306a36Sopenharmony_ci inode->i_size = symlink_len; 45462306a36Sopenharmony_ci while (slen > 1) { 45562306a36Sopenharmony_ci rootflag = 0; 45662306a36Sopenharmony_ci switch (slp->flags & ~1) { 45762306a36Sopenharmony_ci case 0: 45862306a36Sopenharmony_ci inode->i_size += 45962306a36Sopenharmony_ci slp->len; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case 2: 46262306a36Sopenharmony_ci inode->i_size += 1; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case 4: 46562306a36Sopenharmony_ci inode->i_size += 2; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case 8: 46862306a36Sopenharmony_ci rootflag = 1; 46962306a36Sopenharmony_ci inode->i_size += 1; 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci default: 47262306a36Sopenharmony_ci printk("Symlink component flag " 47362306a36Sopenharmony_ci "not implemented\n"); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci slen -= slp->len + 2; 47662306a36Sopenharmony_ci oldslp = slp; 47762306a36Sopenharmony_ci slp = (struct SL_component *) 47862306a36Sopenharmony_ci (((char *)slp) + slp->len + 2); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (slen < 2) { 48162306a36Sopenharmony_ci if (((rr->u.SL. 48262306a36Sopenharmony_ci flags & 1) != 0) 48362306a36Sopenharmony_ci && 48462306a36Sopenharmony_ci ((oldslp-> 48562306a36Sopenharmony_ci flags & 1) == 0)) 48662306a36Sopenharmony_ci inode->i_size += 48762306a36Sopenharmony_ci 1; 48862306a36Sopenharmony_ci break; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * If this component record isn't 49362306a36Sopenharmony_ci * continued, then append a '/'. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci if (!rootflag 49662306a36Sopenharmony_ci && (oldslp->flags & 1) == 0) 49762306a36Sopenharmony_ci inode->i_size += 1; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci symlink_len = inode->i_size; 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci case SIG('R', 'E'): 50362306a36Sopenharmony_ci printk(KERN_WARNING "Attempt to read inode for " 50462306a36Sopenharmony_ci "relocated directory\n"); 50562306a36Sopenharmony_ci goto out; 50662306a36Sopenharmony_ci case SIG('C', 'L'): 50762306a36Sopenharmony_ci if (flags & RR_RELOC_DE) { 50862306a36Sopenharmony_ci printk(KERN_ERR 50962306a36Sopenharmony_ci "ISOFS: Recursive directory relocation " 51062306a36Sopenharmony_ci "is not supported\n"); 51162306a36Sopenharmony_ci goto eio; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci reloc_block = isonum_733(rr->u.CL.location); 51462306a36Sopenharmony_ci if (reloc_block == ISOFS_I(inode)->i_iget5_block && 51562306a36Sopenharmony_ci ISOFS_I(inode)->i_iget5_offset == 0) { 51662306a36Sopenharmony_ci printk(KERN_ERR 51762306a36Sopenharmony_ci "ISOFS: Directory relocation points to " 51862306a36Sopenharmony_ci "itself\n"); 51962306a36Sopenharmony_ci goto eio; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci ISOFS_I(inode)->i_first_extent = reloc_block; 52262306a36Sopenharmony_ci reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0); 52362306a36Sopenharmony_ci if (IS_ERR(reloc)) { 52462306a36Sopenharmony_ci ret = PTR_ERR(reloc); 52562306a36Sopenharmony_ci goto out; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci inode->i_mode = reloc->i_mode; 52862306a36Sopenharmony_ci set_nlink(inode, reloc->i_nlink); 52962306a36Sopenharmony_ci inode->i_uid = reloc->i_uid; 53062306a36Sopenharmony_ci inode->i_gid = reloc->i_gid; 53162306a36Sopenharmony_ci inode->i_rdev = reloc->i_rdev; 53262306a36Sopenharmony_ci inode->i_size = reloc->i_size; 53362306a36Sopenharmony_ci inode->i_blocks = reloc->i_blocks; 53462306a36Sopenharmony_ci inode->i_atime = reloc->i_atime; 53562306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, inode_get_ctime(reloc)); 53662306a36Sopenharmony_ci inode->i_mtime = reloc->i_mtime; 53762306a36Sopenharmony_ci iput(reloc); 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci#ifdef CONFIG_ZISOFS 54062306a36Sopenharmony_ci case SIG('Z', 'F'): { 54162306a36Sopenharmony_ci int algo; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (ISOFS_SB(inode->i_sb)->s_nocompress) 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci algo = isonum_721(rr->u.ZF.algorithm); 54662306a36Sopenharmony_ci if (algo == SIG('p', 'z')) { 54762306a36Sopenharmony_ci int block_shift = 54862306a36Sopenharmony_ci isonum_711(&rr->u.ZF.parms[1]); 54962306a36Sopenharmony_ci if (block_shift > 17) { 55062306a36Sopenharmony_ci printk(KERN_WARNING "isofs: " 55162306a36Sopenharmony_ci "Can't handle ZF block " 55262306a36Sopenharmony_ci "size of 2^%d\n", 55362306a36Sopenharmony_ci block_shift); 55462306a36Sopenharmony_ci } else { 55562306a36Sopenharmony_ci /* 55662306a36Sopenharmony_ci * Note: we don't change 55762306a36Sopenharmony_ci * i_blocks here 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci ISOFS_I(inode)->i_file_format = 56062306a36Sopenharmony_ci isofs_file_compressed; 56162306a36Sopenharmony_ci /* 56262306a36Sopenharmony_ci * Parameters to compression 56362306a36Sopenharmony_ci * algorithm (header size, 56462306a36Sopenharmony_ci * block size) 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci ISOFS_I(inode)->i_format_parm[0] = 56762306a36Sopenharmony_ci isonum_711(&rr->u.ZF.parms[0]); 56862306a36Sopenharmony_ci ISOFS_I(inode)->i_format_parm[1] = 56962306a36Sopenharmony_ci isonum_711(&rr->u.ZF.parms[1]); 57062306a36Sopenharmony_ci inode->i_size = 57162306a36Sopenharmony_ci isonum_733(rr->u.ZF. 57262306a36Sopenharmony_ci real_size); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci } else { 57562306a36Sopenharmony_ci printk(KERN_WARNING 57662306a36Sopenharmony_ci "isofs: Unknown ZF compression " 57762306a36Sopenharmony_ci "algorithm: %c%c\n", 57862306a36Sopenharmony_ci rr->u.ZF.algorithm[0], 57962306a36Sopenharmony_ci rr->u.ZF.algorithm[1]); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci#endif 58462306a36Sopenharmony_ci default: 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci ret = rock_continue(&rs); 58962306a36Sopenharmony_ci if (ret == 0) 59062306a36Sopenharmony_ci goto repeat; 59162306a36Sopenharmony_ci if (ret == 1) 59262306a36Sopenharmony_ci ret = 0; 59362306a36Sopenharmony_ciout: 59462306a36Sopenharmony_ci kfree(rs.buffer); 59562306a36Sopenharmony_ci return ret; 59662306a36Sopenharmony_cieio: 59762306a36Sopenharmony_ci ret = -EIO; 59862306a36Sopenharmony_ci goto out; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci int slen; 60462306a36Sopenharmony_ci int rootflag; 60562306a36Sopenharmony_ci struct SL_component *oldslp; 60662306a36Sopenharmony_ci struct SL_component *slp; 60762306a36Sopenharmony_ci slen = rr->len - 5; 60862306a36Sopenharmony_ci slp = &rr->u.SL.link; 60962306a36Sopenharmony_ci while (slen > 1) { 61062306a36Sopenharmony_ci rootflag = 0; 61162306a36Sopenharmony_ci switch (slp->flags & ~1) { 61262306a36Sopenharmony_ci case 0: 61362306a36Sopenharmony_ci if (slp->len > plimit - rpnt) 61462306a36Sopenharmony_ci return NULL; 61562306a36Sopenharmony_ci memcpy(rpnt, slp->text, slp->len); 61662306a36Sopenharmony_ci rpnt += slp->len; 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case 2: 61962306a36Sopenharmony_ci if (rpnt >= plimit) 62062306a36Sopenharmony_ci return NULL; 62162306a36Sopenharmony_ci *rpnt++ = '.'; 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci case 4: 62462306a36Sopenharmony_ci if (2 > plimit - rpnt) 62562306a36Sopenharmony_ci return NULL; 62662306a36Sopenharmony_ci *rpnt++ = '.'; 62762306a36Sopenharmony_ci *rpnt++ = '.'; 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case 8: 63062306a36Sopenharmony_ci if (rpnt >= plimit) 63162306a36Sopenharmony_ci return NULL; 63262306a36Sopenharmony_ci rootflag = 1; 63362306a36Sopenharmony_ci *rpnt++ = '/'; 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci default: 63662306a36Sopenharmony_ci printk("Symlink component flag not implemented (%d)\n", 63762306a36Sopenharmony_ci slp->flags); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci slen -= slp->len + 2; 64062306a36Sopenharmony_ci oldslp = slp; 64162306a36Sopenharmony_ci slp = (struct SL_component *)((char *)slp + slp->len + 2); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (slen < 2) { 64462306a36Sopenharmony_ci /* 64562306a36Sopenharmony_ci * If there is another SL record, and this component 64662306a36Sopenharmony_ci * record isn't continued, then add a slash. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci if ((!rootflag) && (rr->u.SL.flags & 1) && 64962306a36Sopenharmony_ci !(oldslp->flags & 1)) { 65062306a36Sopenharmony_ci if (rpnt >= plimit) 65162306a36Sopenharmony_ci return NULL; 65262306a36Sopenharmony_ci *rpnt++ = '/'; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* 65862306a36Sopenharmony_ci * If this component record isn't continued, then append a '/'. 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci if (!rootflag && !(oldslp->flags & 1)) { 66162306a36Sopenharmony_ci if (rpnt >= plimit) 66262306a36Sopenharmony_ci return NULL; 66362306a36Sopenharmony_ci *rpnt++ = '/'; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci return rpnt; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ciint parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode, 67062306a36Sopenharmony_ci int relocated) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci int flags = relocated ? RR_RELOC_DE : 0; 67362306a36Sopenharmony_ci int result = parse_rock_ridge_inode_internal(de, inode, flags); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* 67662306a36Sopenharmony_ci * if rockridge flag was reset and we didn't look for attributes 67762306a36Sopenharmony_ci * behind eventual XA attributes, have a look there 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) 68062306a36Sopenharmony_ci && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { 68162306a36Sopenharmony_ci result = parse_rock_ridge_inode_internal(de, inode, 68262306a36Sopenharmony_ci flags | RR_REGARD_XA); 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci return result; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci/* 68862306a36Sopenharmony_ci * read_folio() for symlinks: reads symlink contents into the folio and either 68962306a36Sopenharmony_ci * makes it uptodate and returns 0 or returns error (-EIO) 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_cistatic int rock_ridge_symlink_read_folio(struct file *file, struct folio *folio) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct page *page = &folio->page; 69462306a36Sopenharmony_ci struct inode *inode = page->mapping->host; 69562306a36Sopenharmony_ci struct iso_inode_info *ei = ISOFS_I(inode); 69662306a36Sopenharmony_ci struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); 69762306a36Sopenharmony_ci char *link = page_address(page); 69862306a36Sopenharmony_ci unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 69962306a36Sopenharmony_ci struct buffer_head *bh; 70062306a36Sopenharmony_ci char *rpnt = link; 70162306a36Sopenharmony_ci unsigned char *pnt; 70262306a36Sopenharmony_ci struct iso_directory_record *raw_de; 70362306a36Sopenharmony_ci unsigned long block, offset; 70462306a36Sopenharmony_ci int sig; 70562306a36Sopenharmony_ci struct rock_ridge *rr; 70662306a36Sopenharmony_ci struct rock_state rs; 70762306a36Sopenharmony_ci int ret; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (!sbi->s_rock) 71062306a36Sopenharmony_ci goto error; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci init_rock_state(&rs, inode); 71362306a36Sopenharmony_ci block = ei->i_iget5_block; 71462306a36Sopenharmony_ci bh = sb_bread(inode->i_sb, block); 71562306a36Sopenharmony_ci if (!bh) 71662306a36Sopenharmony_ci goto out_noread; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci offset = ei->i_iget5_offset; 71962306a36Sopenharmony_ci pnt = (unsigned char *)bh->b_data + offset; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci raw_de = (struct iso_directory_record *)pnt; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* 72462306a36Sopenharmony_ci * If we go past the end of the buffer, there is some sort of error. 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ci if (offset + *pnt > bufsize) 72762306a36Sopenharmony_ci goto out_bad_span; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* 73062306a36Sopenharmony_ci * Now test for possible Rock Ridge extensions which will override 73162306a36Sopenharmony_ci * some of these numbers in the inode structure. 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci setup_rock_ridge(raw_de, inode, &rs); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cirepeat: 73762306a36Sopenharmony_ci while (rs.len > 2) { /* There may be one byte for padding somewhere */ 73862306a36Sopenharmony_ci rr = (struct rock_ridge *)rs.chr; 73962306a36Sopenharmony_ci if (rr->len < 3) 74062306a36Sopenharmony_ci goto out; /* Something got screwed up here */ 74162306a36Sopenharmony_ci sig = isonum_721(rs.chr); 74262306a36Sopenharmony_ci if (rock_check_overflow(&rs, sig)) 74362306a36Sopenharmony_ci goto out; 74462306a36Sopenharmony_ci rs.chr += rr->len; 74562306a36Sopenharmony_ci rs.len -= rr->len; 74662306a36Sopenharmony_ci if (rs.len < 0) 74762306a36Sopenharmony_ci goto out; /* corrupted isofs */ 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci switch (sig) { 75062306a36Sopenharmony_ci case SIG('R', 'R'): 75162306a36Sopenharmony_ci if ((rr->u.RR.flags[0] & RR_SL) == 0) 75262306a36Sopenharmony_ci goto out; 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci case SIG('S', 'P'): 75562306a36Sopenharmony_ci if (check_sp(rr, inode)) 75662306a36Sopenharmony_ci goto out; 75762306a36Sopenharmony_ci break; 75862306a36Sopenharmony_ci case SIG('S', 'L'): 75962306a36Sopenharmony_ci rpnt = get_symlink_chunk(rpnt, rr, 76062306a36Sopenharmony_ci link + (PAGE_SIZE - 1)); 76162306a36Sopenharmony_ci if (rpnt == NULL) 76262306a36Sopenharmony_ci goto out; 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci case SIG('C', 'E'): 76562306a36Sopenharmony_ci /* This tells is if there is a continuation record */ 76662306a36Sopenharmony_ci rs.cont_extent = isonum_733(rr->u.CE.extent); 76762306a36Sopenharmony_ci rs.cont_offset = isonum_733(rr->u.CE.offset); 76862306a36Sopenharmony_ci rs.cont_size = isonum_733(rr->u.CE.size); 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci default: 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci ret = rock_continue(&rs); 77562306a36Sopenharmony_ci if (ret == 0) 77662306a36Sopenharmony_ci goto repeat; 77762306a36Sopenharmony_ci if (ret < 0) 77862306a36Sopenharmony_ci goto fail; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (rpnt == link) 78162306a36Sopenharmony_ci goto fail; 78262306a36Sopenharmony_ci brelse(bh); 78362306a36Sopenharmony_ci *rpnt = '\0'; 78462306a36Sopenharmony_ci SetPageUptodate(page); 78562306a36Sopenharmony_ci unlock_page(page); 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* error exit from macro */ 78962306a36Sopenharmony_ciout: 79062306a36Sopenharmony_ci kfree(rs.buffer); 79162306a36Sopenharmony_ci goto fail; 79262306a36Sopenharmony_ciout_noread: 79362306a36Sopenharmony_ci printk("unable to read i-node block"); 79462306a36Sopenharmony_ci goto fail; 79562306a36Sopenharmony_ciout_bad_span: 79662306a36Sopenharmony_ci printk("symlink spans iso9660 blocks\n"); 79762306a36Sopenharmony_cifail: 79862306a36Sopenharmony_ci brelse(bh); 79962306a36Sopenharmony_cierror: 80062306a36Sopenharmony_ci SetPageError(page); 80162306a36Sopenharmony_ci unlock_page(page); 80262306a36Sopenharmony_ci return -EIO; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ciconst struct address_space_operations isofs_symlink_aops = { 80662306a36Sopenharmony_ci .read_folio = rock_ridge_symlink_read_folio 80762306a36Sopenharmony_ci}; 808