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 <linux/buffer_head.h> 31 #include "udf_i.h" 32 33 static void udf_pc_to_char(struct super_block *sb, unsigned char *from, 34 int fromlen, unsigned char *to) 35 { 36 struct pathComponent *pc; 37 int elen = 0; 38 unsigned char *p = to; 39 40 while (elen < fromlen) { 41 pc = (struct pathComponent *)(from + elen); 42 switch (pc->componentType) { 43 case 1: 44 /* 45 * Symlink points to some place which should be agreed 46 * upon between originator and receiver of the media. Ignore. 47 */ 48 if (pc->lengthComponentIdent > 0) 49 break; 50 /* Fall through */ 51 case 2: 52 p = to; 53 *p++ = '/'; 54 break; 55 case 3: 56 memcpy(p, "../", 3); 57 p += 3; 58 break; 59 case 4: 60 memcpy(p, "./", 2); 61 p += 2; 62 /* that would be . - just ignore */ 63 break; 64 case 5: 65 p += udf_get_filename(sb, pc->componentIdent, p, 66 pc->lengthComponentIdent); 67 *p++ = '/'; 68 break; 69 } 70 elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; 71 } 72 if (p > to + 1) 73 p[-1] = '\0'; 74 else 75 p[0] = '\0'; 76 } 77 78 static int udf_symlink_filler(struct file *file, struct page *page) 79 { 80 struct inode *inode = page->mapping->host; 81 struct buffer_head *bh = NULL; 82 unsigned char *symlink; 83 int err = -EIO; 84 unsigned char *p = kmap(page); 85 struct udf_inode_info *iinfo; 86 uint32_t pos; 87 88 iinfo = UDF_I(inode); 89 pos = udf_block_map(inode, 0); 90 91 down_read(&iinfo->i_data_sem); 92 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 93 symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr; 94 } else { 95 bh = sb_bread(inode->i_sb, pos); 96 97 if (!bh) 98 goto out; 99 100 symlink = bh->b_data; 101 } 102 103 udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); 104 brelse(bh); 105 106 up_read(&iinfo->i_data_sem); 107 SetPageUptodate(page); 108 kunmap(page); 109 unlock_page(page); 110 return 0; 111 112 out: 113 up_read(&iinfo->i_data_sem); 114 SetPageError(page); 115 kunmap(page); 116 unlock_page(page); 117 return err; 118 } 119 120 /* 121 * symlinks can't do much... 122 */ 123 const struct address_space_operations udf_symlink_aops = { 124 .readpage = udf_symlink_filler, 125 }; 126