Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
symlink.c
Go to the documentation of this file.
1 /*
2  * Squashfs - a compressed read only filesystem for Linux
3  *
4  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
5  * Phillip Lougher <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2,
10  * or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * symlink.c
22  */
23 
24 /*
25  * This file implements code to handle symbolic links.
26  *
27  * The data contents of symbolic links are stored inside the symbolic
28  * link inode within the inode table. This allows the normally small symbolic
29  * link to be compressed as part of the inode table, achieving much greater
30  * compression than if the symbolic link was compressed individually.
31  */
32 
33 #include <linux/fs.h>
34 #include <linux/vfs.h>
35 #include <linux/kernel.h>
36 #include <linux/string.h>
37 #include <linux/pagemap.h>
38 #include <linux/xattr.h>
39 
40 #include "squashfs_fs.h"
41 #include "squashfs_fs_sb.h"
42 #include "squashfs_fs_i.h"
43 #include "squashfs.h"
44 #include "xattr.h"
45 
46 static int squashfs_symlink_readpage(struct file *file, struct page *page)
47 {
48  struct inode *inode = page->mapping->host;
49  struct super_block *sb = inode->i_sb;
50  struct squashfs_sb_info *msblk = sb->s_fs_info;
51  int index = page->index << PAGE_CACHE_SHIFT;
52  u64 block = squashfs_i(inode)->start;
53  int offset = squashfs_i(inode)->offset;
54  int length = min_t(int, i_size_read(inode) - index, PAGE_CACHE_SIZE);
55  int bytes, copied;
56  void *pageaddr;
58 
59  TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
60  "%llx, offset %x\n", page->index, block, offset);
61 
62  /*
63  * Skip index bytes into symlink metadata.
64  */
65  if (index) {
66  bytes = squashfs_read_metadata(sb, NULL, &block, &offset,
67  index);
68  if (bytes < 0) {
69  ERROR("Unable to read symlink [%llx:%x]\n",
70  squashfs_i(inode)->start,
71  squashfs_i(inode)->offset);
72  goto error_out;
73  }
74  }
75 
76  /*
77  * Read length bytes from symlink metadata. Squashfs_read_metadata
78  * is not used here because it can sleep and we want to use
79  * kmap_atomic to map the page. Instead call the underlying
80  * squashfs_cache_get routine. As length bytes may overlap metadata
81  * blocks, we may need to call squashfs_cache_get multiple times.
82  */
83  for (bytes = 0; bytes < length; offset = 0, bytes += copied) {
84  entry = squashfs_cache_get(sb, msblk->block_cache, block, 0);
85  if (entry->error) {
86  ERROR("Unable to read symlink [%llx:%x]\n",
87  squashfs_i(inode)->start,
88  squashfs_i(inode)->offset);
89  squashfs_cache_put(entry);
90  goto error_out;
91  }
92 
93  pageaddr = kmap_atomic(page);
94  copied = squashfs_copy_data(pageaddr + bytes, entry, offset,
95  length - bytes);
96  if (copied == length - bytes)
97  memset(pageaddr + length, 0, PAGE_CACHE_SIZE - length);
98  else
99  block = entry->next_index;
100  kunmap_atomic(pageaddr);
101  squashfs_cache_put(entry);
102  }
103 
104  flush_dcache_page(page);
105  SetPageUptodate(page);
106  unlock_page(page);
107  return 0;
108 
109 error_out:
110  SetPageError(page);
111  unlock_page(page);
112  return 0;
113 }
114 
115 
117  .readpage = squashfs_symlink_readpage
118 };
119 
121  .readlink = generic_readlink,
122  .follow_link = page_follow_link_light,
123  .put_link = page_put_link,
124  .getxattr = generic_getxattr,
125  .listxattr = squashfs_listxattr
126 };
127