mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
![Thomas Gleixner](/assets/img/avatar_default.png)
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not write to the free software foundation 51 franklin street fifth floor boston ma 02110 1301 usa extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 23 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190520170857.458548087@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
111 lines
3 KiB
C
111 lines
3 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Squashfs - a compressed read only filesystem for Linux
|
|
*
|
|
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
|
* Phillip Lougher <phillip@squashfs.org.uk>
|
|
*
|
|
* symlink.c
|
|
*/
|
|
|
|
/*
|
|
* This file implements code to handle symbolic links.
|
|
*
|
|
* The data contents of symbolic links are stored inside the symbolic
|
|
* link inode within the inode table. This allows the normally small symbolic
|
|
* link to be compressed as part of the inode table, achieving much greater
|
|
* compression than if the symbolic link was compressed individually.
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/vfs.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/xattr.h>
|
|
|
|
#include "squashfs_fs.h"
|
|
#include "squashfs_fs_sb.h"
|
|
#include "squashfs_fs_i.h"
|
|
#include "squashfs.h"
|
|
#include "xattr.h"
|
|
|
|
static int squashfs_symlink_readpage(struct file *file, struct page *page)
|
|
{
|
|
struct inode *inode = page->mapping->host;
|
|
struct super_block *sb = inode->i_sb;
|
|
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
|
int index = page->index << PAGE_SHIFT;
|
|
u64 block = squashfs_i(inode)->start;
|
|
int offset = squashfs_i(inode)->offset;
|
|
int length = min_t(int, i_size_read(inode) - index, PAGE_SIZE);
|
|
int bytes, copied;
|
|
void *pageaddr;
|
|
struct squashfs_cache_entry *entry;
|
|
|
|
TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
|
|
"%llx, offset %x\n", page->index, block, offset);
|
|
|
|
/*
|
|
* Skip index bytes into symlink metadata.
|
|
*/
|
|
if (index) {
|
|
bytes = squashfs_read_metadata(sb, NULL, &block, &offset,
|
|
index);
|
|
if (bytes < 0) {
|
|
ERROR("Unable to read symlink [%llx:%x]\n",
|
|
squashfs_i(inode)->start,
|
|
squashfs_i(inode)->offset);
|
|
goto error_out;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read length bytes from symlink metadata. Squashfs_read_metadata
|
|
* is not used here because it can sleep and we want to use
|
|
* kmap_atomic to map the page. Instead call the underlying
|
|
* squashfs_cache_get routine. As length bytes may overlap metadata
|
|
* blocks, we may need to call squashfs_cache_get multiple times.
|
|
*/
|
|
for (bytes = 0; bytes < length; offset = 0, bytes += copied) {
|
|
entry = squashfs_cache_get(sb, msblk->block_cache, block, 0);
|
|
if (entry->error) {
|
|
ERROR("Unable to read symlink [%llx:%x]\n",
|
|
squashfs_i(inode)->start,
|
|
squashfs_i(inode)->offset);
|
|
squashfs_cache_put(entry);
|
|
goto error_out;
|
|
}
|
|
|
|
pageaddr = kmap_atomic(page);
|
|
copied = squashfs_copy_data(pageaddr + bytes, entry, offset,
|
|
length - bytes);
|
|
if (copied == length - bytes)
|
|
memset(pageaddr + length, 0, PAGE_SIZE - length);
|
|
else
|
|
block = entry->next_index;
|
|
kunmap_atomic(pageaddr);
|
|
squashfs_cache_put(entry);
|
|
}
|
|
|
|
flush_dcache_page(page);
|
|
SetPageUptodate(page);
|
|
unlock_page(page);
|
|
return 0;
|
|
|
|
error_out:
|
|
SetPageError(page);
|
|
unlock_page(page);
|
|
return 0;
|
|
}
|
|
|
|
|
|
const struct address_space_operations squashfs_symlink_aops = {
|
|
.readpage = squashfs_symlink_readpage
|
|
};
|
|
|
|
const struct inode_operations squashfs_symlink_inode_ops = {
|
|
.get_link = page_get_link,
|
|
.listxattr = squashfs_listxattr
|
|
};
|
|
|