]>
Commit | Line | Data |
---|---|---|
68252eb5 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1dc4bba3 PL |
2 | /* |
3 | * Squashfs - a compressed read only filesystem for Linux | |
4 | * | |
5 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | |
d7f2ff67 | 6 | * Phillip Lougher <phillip@squashfs.org.uk> |
1dc4bba3 | 7 | * |
1dc4bba3 PL |
8 | * symlink.c |
9 | */ | |
10 | ||
11 | /* | |
12 | * This file implements code to handle symbolic links. | |
13 | * | |
14 | * The data contents of symbolic links are stored inside the symbolic | |
15 | * link inode within the inode table. This allows the normally small symbolic | |
16 | * link to be compressed as part of the inode table, achieving much greater | |
17 | * compression than if the symbolic link was compressed individually. | |
18 | */ | |
19 | ||
20 | #include <linux/fs.h> | |
21 | #include <linux/vfs.h> | |
22 | #include <linux/kernel.h> | |
1dc4bba3 PL |
23 | #include <linux/string.h> |
24 | #include <linux/pagemap.h> | |
67f66cc6 | 25 | #include <linux/xattr.h> |
1dc4bba3 PL |
26 | |
27 | #include "squashfs_fs.h" | |
28 | #include "squashfs_fs_sb.h" | |
29 | #include "squashfs_fs_i.h" | |
30 | #include "squashfs.h" | |
01e5b4e4 | 31 | #include "xattr.h" |
1dc4bba3 PL |
32 | |
33 | static int squashfs_symlink_readpage(struct file *file, struct page *page) | |
34 | { | |
35 | struct inode *inode = page->mapping->host; | |
36 | struct super_block *sb = inode->i_sb; | |
37 | struct squashfs_sb_info *msblk = sb->s_fs_info; | |
09cbfeaf | 38 | int index = page->index << PAGE_SHIFT; |
1dc4bba3 PL |
39 | u64 block = squashfs_i(inode)->start; |
40 | int offset = squashfs_i(inode)->offset; | |
09cbfeaf | 41 | int length = min_t(int, i_size_read(inode) - index, PAGE_SIZE); |
1dc4bba3 PL |
42 | int bytes, copied; |
43 | void *pageaddr; | |
44 | struct squashfs_cache_entry *entry; | |
45 | ||
46 | TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " | |
47 | "%llx, offset %x\n", page->index, block, offset); | |
48 | ||
49 | /* | |
50 | * Skip index bytes into symlink metadata. | |
51 | */ | |
52 | if (index) { | |
53 | bytes = squashfs_read_metadata(sb, NULL, &block, &offset, | |
54 | index); | |
55 | if (bytes < 0) { | |
56 | ERROR("Unable to read symlink [%llx:%x]\n", | |
57 | squashfs_i(inode)->start, | |
58 | squashfs_i(inode)->offset); | |
59 | goto error_out; | |
60 | } | |
61 | } | |
62 | ||
63 | /* | |
64 | * Read length bytes from symlink metadata. Squashfs_read_metadata | |
65 | * is not used here because it can sleep and we want to use | |
66 | * kmap_atomic to map the page. Instead call the underlying | |
67 | * squashfs_cache_get routine. As length bytes may overlap metadata | |
68 | * blocks, we may need to call squashfs_cache_get multiple times. | |
69 | */ | |
70 | for (bytes = 0; bytes < length; offset = 0, bytes += copied) { | |
71 | entry = squashfs_cache_get(sb, msblk->block_cache, block, 0); | |
72 | if (entry->error) { | |
73 | ERROR("Unable to read symlink [%llx:%x]\n", | |
74 | squashfs_i(inode)->start, | |
75 | squashfs_i(inode)->offset); | |
76 | squashfs_cache_put(entry); | |
77 | goto error_out; | |
78 | } | |
79 | ||
53b55e55 | 80 | pageaddr = kmap_atomic(page); |
1dc4bba3 PL |
81 | copied = squashfs_copy_data(pageaddr + bytes, entry, offset, |
82 | length - bytes); | |
83 | if (copied == length - bytes) | |
09cbfeaf | 84 | memset(pageaddr + length, 0, PAGE_SIZE - length); |
1dc4bba3 PL |
85 | else |
86 | block = entry->next_index; | |
53b55e55 | 87 | kunmap_atomic(pageaddr); |
1dc4bba3 PL |
88 | squashfs_cache_put(entry); |
89 | } | |
90 | ||
91 | flush_dcache_page(page); | |
92 | SetPageUptodate(page); | |
93 | unlock_page(page); | |
94 | return 0; | |
95 | ||
96 | error_out: | |
97 | SetPageError(page); | |
98 | unlock_page(page); | |
99 | return 0; | |
100 | } | |
101 | ||
102 | ||
103 | const struct address_space_operations squashfs_symlink_aops = { | |
104 | .readpage = squashfs_symlink_readpage | |
105 | }; | |
67f66cc6 PL |
106 | |
107 | const struct inode_operations squashfs_symlink_inode_ops = { | |
6b255391 | 108 | .get_link = page_get_link, |
67f66cc6 PL |
109 | .listxattr = squashfs_listxattr |
110 | }; | |
111 |