root/fs/squashfs/symlink.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. squashfs_symlink_readpage

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Squashfs - a compressed read only filesystem for Linux
   4  *
   5  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
   6  * Phillip Lougher <phillip@squashfs.org.uk>
   7  *
   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>
  23 #include <linux/string.h>
  24 #include <linux/pagemap.h>
  25 #include <linux/xattr.h>
  26 
  27 #include "squashfs_fs.h"
  28 #include "squashfs_fs_sb.h"
  29 #include "squashfs_fs_i.h"
  30 #include "squashfs.h"
  31 #include "xattr.h"
  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;
  38         int index = page->index << PAGE_SHIFT;
  39         u64 block = squashfs_i(inode)->start;
  40         int offset = squashfs_i(inode)->offset;
  41         int length = min_t(int, i_size_read(inode) - index, PAGE_SIZE);
  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 
  80                 pageaddr = kmap_atomic(page);
  81                 copied = squashfs_copy_data(pageaddr + bytes, entry, offset,
  82                                                                 length - bytes);
  83                 if (copied == length - bytes)
  84                         memset(pageaddr + length, 0, PAGE_SIZE - length);
  85                 else
  86                         block = entry->next_index;
  87                 kunmap_atomic(pageaddr);
  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 };
 106 
 107 const struct inode_operations squashfs_symlink_inode_ops = {
 108         .get_link = page_get_link,
 109         .listxattr = squashfs_listxattr
 110 };
 111 

/* [<][>][^][v][top][bottom][index][help] */