Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | /* * symlink.c * * PURPOSE * Symlink handling routines for the OSTA-UDF(tm) filesystem. * * CONTACTS * E-mail regarding any portion of the Linux UDF file system should be * directed to the development team mailing list (run by majordomo): * linux_udf@hootie.lvld.hp.com * * COPYRIGHT * This file is distributed under the terms of the GNU General Public * License (GPL). Copies of the GPL can be obtained from: * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. * * (C) 1998-2000 Ben Fennema * (C) 1999 Stelias Computing Inc * * HISTORY * * 04/16/99 blf Created. * */ #include "udfdecl.h" #include <asm/uaccess.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/udf_fs.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/stat.h> #include <linux/malloc.h> #include <linux/pagemap.h> #include "udf_i.h" static void udf_pc_to_char(char *from, int fromlen, char *to) { struct PathComponent *pc; int elen = 0; char *p = to; while (elen < fromlen) { pc = (struct PathComponent *)(from + elen); switch (pc->componentType) { case 1: if (pc->lengthComponentIdent == 0) { p = to; *p++ = '/'; } break; case 3: memcpy(p, "../", 3); p += 3; break; case 4: memcpy(p, "./", 2); p += 2; /* that would be . - just ignore */ break; case 5: memcpy(p, pc->componentIdent, pc->lengthComponentIdent); p += pc->lengthComponentIdent; *p++ = '/'; } elen += sizeof(struct PathComponent) + pc->lengthComponentIdent; } if (p > to+1) p[-1] = '\0'; else p[0] = '\0'; } static int udf_symlink_filler(struct dentry * dentry, struct page *page) { struct inode *inode = dentry->d_inode; struct buffer_head *bh = NULL; char *symlink; int err = -EIO; char *p = (char *)kmap(page); if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) { bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize); if (!bh) goto out; symlink = bh->b_data + udf_file_entry_alloc_offset(inode); } else { bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize); if (!bh) goto out; symlink = bh->b_data; } udf_pc_to_char(symlink, inode->i_size, p); udf_release_data(bh); SetPageUptodate(page); kunmap(page); UnlockPage(page); return 0; out: SetPageError(page); kunmap(page); UnlockPage(page); return err; } /* * symlinks can't do much... */ struct address_space_operations udf_symlink_aops = { readpage: udf_symlink_filler, }; |