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 <asm/uaccess.h> 24 #include <linux/errno.h> 25 #include <linux/fs.h> 26 #include <linux/udf_fs.h> 27 #include <linux/time.h> 28 #include <linux/mm.h> 29 #include <linux/stat.h> 30 #include <linux/slab.h> 31 #include <linux/pagemap.h> 32 #include <linux/smp_lock.h> 33 #include <linux/buffer_head.h> 34 #include "udf_i.h" 35 36 static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char *to) 37 { 38 struct pathComponent *pc; 39 int elen = 0; 40 char *p = to; 41 42 while (elen < fromlen) 43 { 44 pc = (struct pathComponent *)(from + elen); 45 switch (pc->componentType) 46 { 47 case 1: 48 if (pc->lengthComponentIdent == 0) 49 { 50 p = to; 51 *p++ = '/'; 52 } 53 break; 54 case 3: 55 memcpy(p, "../", 3); 56 p += 3; 57 break; 58 case 4: 59 memcpy(p, "./", 2); 60 p += 2; 61 /* that would be . - just ignore */ 62 break; 63 case 5: 64 p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent); 65 *p++ = '/'; 66 break; 67 } 68 elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; 69 } 70 if (p > to+1) 71 p[-1] = '\0'; 72 else 73 p[0] = '\0'; 74 } 75 76 static int udf_symlink_filler(struct file *file, struct page *page) 77 { 78 struct inode *inode = page->mapping->host; 79 struct buffer_head *bh = NULL; 80 char *symlink; 81 int err = -EIO; 82 char *p = kmap(page); 83 84 lock_kernel(); 85 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) 86 symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); 87 else 88 { 89 bh = sb_bread(inode->i_sb, udf_block_map(inode, 0)); 90 91 if (!bh) 92 goto out; 93 94 symlink = bh->b_data; 95 } 96 97 udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); 98 brelse(bh); 99 100 unlock_kernel(); 101 SetPageUptodate(page); 102 kunmap(page); 103 unlock_page(page); 104 return 0; 105 out: 106 unlock_kernel(); 107 SetPageError(page); 108 kunmap(page); 109 unlock_page(page); 110 return err; 111 } 112 113 /* 114 * symlinks can't do much... 115 */ 116 const struct address_space_operations udf_symlink_aops = { 117 .readpage = udf_symlink_filler, 118 }; 119