symlink.c (4436B)
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 32static 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 104static 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; 111 unsigned char *p = page_address(page); 112 struct udf_inode_info *iinfo; 113 uint32_t pos; 114 115 /* We don't support symlinks longer than one block */ 116 if (inode->i_size > inode->i_sb->s_blocksize) { 117 err = -ENAMETOOLONG; 118 goto out_unmap; 119 } 120 121 iinfo = UDF_I(inode); 122 pos = udf_block_map(inode, 0); 123 124 down_read(&iinfo->i_data_sem); 125 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 126 symlink = iinfo->i_data + iinfo->i_lenEAttr; 127 } else { 128 bh = sb_bread(inode->i_sb, pos); 129 130 if (!bh) { 131 err = -EIO; 132 goto out_unlock_inode; 133 } 134 135 symlink = bh->b_data; 136 } 137 138 err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE); 139 brelse(bh); 140 if (err) 141 goto out_unlock_inode; 142 143 up_read(&iinfo->i_data_sem); 144 SetPageUptodate(page); 145 unlock_page(page); 146 return 0; 147 148out_unlock_inode: 149 up_read(&iinfo->i_data_sem); 150 SetPageError(page); 151out_unmap: 152 unlock_page(page); 153 return err; 154} 155 156static int udf_symlink_getattr(struct user_namespace *mnt_userns, 157 const struct path *path, struct kstat *stat, 158 u32 request_mask, unsigned int flags) 159{ 160 struct dentry *dentry = path->dentry; 161 struct inode *inode = d_backing_inode(dentry); 162 struct page *page; 163 164 generic_fillattr(&init_user_ns, inode, stat); 165 page = read_mapping_page(inode->i_mapping, 0, NULL); 166 if (IS_ERR(page)) 167 return PTR_ERR(page); 168 /* 169 * UDF uses non-trivial encoding of symlinks so i_size does not match 170 * number of characters reported by readlink(2) which apparently some 171 * applications expect. Also POSIX says that "The value returned in the 172 * st_size field shall be the length of the contents of the symbolic 173 * link, and shall not count a trailing null if one is present." So 174 * let's report the length of string returned by readlink(2) for 175 * st_size. 176 */ 177 stat->size = strlen(page_address(page)); 178 put_page(page); 179 180 return 0; 181} 182 183/* 184 * symlinks can't do much... 185 */ 186const struct address_space_operations udf_symlink_aops = { 187 .read_folio = udf_symlink_filler, 188}; 189 190const struct inode_operations udf_symlink_inode_operations = { 191 .get_link = page_get_link, 192 .getattr = udf_symlink_getattr, 193};