UBIFS: Change ubifsload to not read beyond the requested size

Until now ubifsload pads the destination with 0 up to a multiple of
UBIFS_BLOCK_SIZE (4KiB) while reading a file to memory. This patch
changes this behaviour to only read to the requested length. This
is either the file length or the length/size provided as parameter
to the ubifsload command.

Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
Stefan Roese 2010-11-01 17:28:00 +01:00
parent 9a2ea578bc
commit b1a14f8a1c

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
* (C) Copyright 2008-2009
* (C) Copyright 2008-2010
* Stefan Roese, DENX Software Engineering, sr@denx.de.
*
* This program is free software; you can redistribute it and/or modify it
@ -567,7 +567,8 @@ dump:
return -EINVAL;
}
static int do_readpage(struct ubifs_info *c, struct inode *inode, struct page *page)
static int do_readpage(struct ubifs_info *c, struct inode *inode,
struct page *page, int last_block_size)
{
void *addr;
int err = 0, i;
@ -601,17 +602,54 @@ static int do_readpage(struct ubifs_info *c, struct inode *inode, struct page *p
err = -ENOENT;
memset(addr, 0, UBIFS_BLOCK_SIZE);
} else {
ret = read_block(inode, addr, block, dn);
if (ret) {
err = ret;
if (err != -ENOENT)
break;
} else if (block + 1 == beyond) {
int dlen = le32_to_cpu(dn->size);
int ilen = i_size & (UBIFS_BLOCK_SIZE - 1);
/*
* Reading last block? Make sure to not write beyond
* the requested size in the destination buffer.
*/
if (((block + 1) == beyond) || last_block_size) {
void *buff;
int dlen;
if (ilen && ilen < dlen)
memset(addr + ilen, 0, dlen - ilen);
/*
* We need to buffer the data locally for the
* last block. This is to not pad the
* destination area to a multiple of
* UBIFS_BLOCK_SIZE.
*/
buff = malloc(UBIFS_BLOCK_SIZE);
if (!buff) {
printf("%s: Error, malloc fails!\n",
__func__);
err = -ENOMEM;
break;
}
/* Read block-size into temp buffer */
ret = read_block(inode, buff, block, dn);
if (ret) {
err = ret;
if (err != -ENOENT) {
free(buff);
break;
}
}
if (last_block_size)
dlen = last_block_size;
else
dlen = le32_to_cpu(dn->size);
/* Now copy required size back to dest */
memcpy(addr, buff, dlen);
free(buff);
} else {
ret = read_block(inode, addr, block, dn);
if (ret) {
err = ret;
if (err != -ENOENT)
break;
}
}
}
if (++i >= UBIFS_BLOCKS_PER_PAGE)
@ -649,6 +687,7 @@ int ubifs_load(char *filename, u32 addr, u32 size)
int err = 0;
int i;
int count;
int last_block_size = 0;
c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
/* ubifs_findfile will resolve symlinks, so we know that we get
@ -684,7 +723,13 @@ int ubifs_load(char *filename, u32 addr, u32 size)
page.index = 0;
page.inode = inode;
for (i = 0; i < count; i++) {
err = do_readpage(c, inode, &page);
/*
* Make sure to not read beyond the requested size
*/
if (((i + 1) == count) && (size < inode->i_size))
last_block_size = size - (i * PAGE_SIZE);
err = do_readpage(c, inode, &page, last_block_size);
if (err)
break;