1 /* 2 * symlink.c 3 * 4 * PURPOSE 5 * Symlink handling routines for the OSTA-UDF(tm) filesystem. 6 * 7 * COPYRIGHT 8 * This file is distributed under the terms of the GNU General Public 9 * License (GPL). Copies of the GPL can be obtained from: 10 * ftp://prep.ai.mit.edu/pub/gnu/GPL 11 * Each contributing author retains all rights to their own work. 12 * 13 * (C) 1998-2001 Ben Fennema 14 * (C) 1999 Stelias Computing Inc 15 * 16 * HISTORY 17 * 18 * 04/16/99 blf Created. 19 * 20 */ 21 22 #include "udfdecl.h" 23 #include <linux/uaccess.h> 24 #include <linux/errno.h> 25 #include <linux/fs.h> 26 #include <linux/time.h> 27 #include <linux/mm.h> 28 #include <linux/stat.h> 29 #include <linux/pagemap.h> 30 #include "udf_i.h" 31 32 static int udf_pc_to_char(struct super_block *sb, unsigned char *from, 33 int fromlen, unsigned char *to, int tolen) 34 { 35 struct pathComponent *pc; 36 int elen = 0; 37 int comp_len; 38 unsigned char *p = to; 39 40 /* Reserve one byte for terminating \0 */ 41 tolen--; 42 while (elen < fromlen) { 43 pc = (struct pathComponent *)(from + elen); 44 elen += sizeof(struct pathComponent); 45 switch (pc->componentType) { 46 case 1: 47 /* 48 * Symlink points to some place which should be agreed 49 * upon between originator and receiver of the media. Ignore. 50 */ 51 if (pc->lengthComponentIdent > 0) { 52 elen += pc->lengthComponentIdent; 53 break; 54 } 55 fallthrough; 56 case 2: 57 if (tolen == 0) 58 return -ENAMETOOLONG; 59 p = to; 60 *p++ = '/'; 61 tolen--; 62 break; 63 case 3: 64 if (tolen < 3) 65 return -ENAMETOOLONG; 66 memcpy(p, "../", 3); 67 p += 3; 68 tolen -= 3; 69 break; 70 case 4: 71 if (tolen < 2) 72 return -ENAMETOOLONG; 73 memcpy(p, "./", 2); 74 p += 2; 75 tolen -= 2; 76 /* that would be . - just ignore */ 77 break; 78 case 5: 79 elen += pc->lengthComponentIdent; 80 if (elen > fromlen) 81 return -EIO; 82 comp_len = udf_get_filename(sb, pc->componentIdent, 83 pc->lengthComponentIdent, 84 p, tolen); 85 if (comp_len < 0) 86 return comp_len; 87 88 p += comp_len; 89 tolen -= comp_len; 90 if (tolen == 0) 91 return -ENAMETOOLONG; 92 *p++ = '/'; 93 tolen--; 94 break; 95 } 96 } 97 if (p > to + 1) 98 p[-1] = '\0'; 99 else 100 p[0] = '\0'; 101 return 0; 102 } 103 104 static int udf_symlink_filler(struct file *file, struct folio *folio) 105 { 106 struct page *page = &folio->page; 107 struct inode *inode = page->mapping->host; 108 struct buffer_head *bh = NULL; 109 unsigned char *symlink; 110 int err = 0; 111 unsigned char *p = page_address(page); 112 struct udf_inode_info *iinfo = UDF_I(inode); 113 114 /* We don't support symlinks longer than one block */ 115 if (inode->i_size > inode->i_sb->s_blocksize) { 116 err = -ENAMETOOLONG; 117 goto out_unlock; 118 } 119 120 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 121 symlink = iinfo->i_data + iinfo->i_lenEAttr; 122 } else { 123 bh = udf_bread(inode, 0, 0, &err); 124 if (!bh) { 125 if (!err) 126 err = -EFSCORRUPTED; 127 goto out_err; 128 } 129 symlink = bh->b_data; 130 } 131 132 err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE); 133 brelse(bh); 134 if (err) 135 goto out_err; 136 137 SetPageUptodate(page); 138 unlock_page(page); 139 return 0; 140 141 out_err: 142 SetPageError(page); 143 out_unlock: 144 unlock_page(page); 145 return err; 146 } 147 148 static int udf_symlink_getattr(struct mnt_idmap *idmap, 149 const struct path *path, struct kstat *stat, 150 u32 request_mask, unsigned int flags) 151 { 152 struct dentry *dentry = path->dentry; 153 struct inode *inode = d_backing_inode(dentry); 154 struct page *page; 155 156 generic_fillattr(&nop_mnt_idmap, inode, stat); 157 page = read_mapping_page(inode->i_mapping, 0, NULL); 158 if (IS_ERR(page)) 159 return PTR_ERR(page); 160 /* 161 * UDF uses non-trivial encoding of symlinks so i_size does not match 162 * number of characters reported by readlink(2) which apparently some 163 * applications expect. Also POSIX says that "The value returned in the 164 * st_size field shall be the length of the contents of the symbolic 165 * link, and shall not count a trailing null if one is present." So 166 * let's report the length of string returned by readlink(2) for 167 * st_size. 168 */ 169 stat->size = strlen(page_address(page)); 170 put_page(page); 171 172 return 0; 173 } 174 175 /* 176 * symlinks can't do much... 177 */ 178 const struct address_space_operations udf_symlink_aops = { 179 .read_folio = udf_symlink_filler, 180 }; 181 182 const struct inode_operations udf_symlink_inode_operations = { 183 .get_link = page_get_link, 184 .getattr = udf_symlink_getattr, 185 }; 186