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