File s390-tools-sles11sp2-cmsfs-fuse_large_files.patch of Package s390-tools
Descripton: cmsfs-fuse: Fix file size calculation for files larger than 2 GB
Symptom: It is not possible to create files larger than 2 GB.
Problem: The file size calculation overflows resulting in a negative value.
Solution: Cast to a longer type before calculating the file size.
Problem-ID: 75609
---
cmsfs-fuse/amap.c | 11 +++---
cmsfs-fuse/cmsfs-fuse.c | 77 +++++++++++++++++++++++++-----------------------
cmsfs-fuse/cmsfs-fuse.h | 6 +--
cmsfs-fuse/edf.h | 2 -
4 files changed, 51 insertions(+), 45 deletions(-)
--- a/cmsfs-fuse/amap.c
+++ b/cmsfs-fuse/amap.c
@@ -49,7 +49,7 @@ static off_t get_amap_addr(int level, of
return cmsfs.amap;
if (level--) {
- ptr = get_fixed_pointer(ptr + block * PTR_SIZE);
+ ptr = get_fixed_pointer(ptr + (off_t ) block * PTR_SIZE);
if (!ptr)
DIE("amap invalid ptr at addr: %lx\n",
ptr + block * PTR_SIZE);
@@ -69,7 +69,7 @@ static void amap_block_set(off_t addr)
u8 entry;
if (block > 0)
- addr -= block * BYTES_PER_BLOCK;
+ addr -= (off_t) block * BYTES_PER_BLOCK;
addr >>= BITS_PER_DATA_BLOCK;
byte = addr / 8;
@@ -97,7 +97,7 @@ static void amap_block_clear(off_t addr)
u8 entry;
if (block > 0)
- addr -= block * BYTES_PER_BLOCK;
+ addr -= (off_t) block * BYTES_PER_BLOCK;
addr >>= BITS_PER_DATA_BLOCK;
byte = addr / 8;
@@ -163,8 +163,9 @@ static off_t __get_free_block(int level,
bit = find_first_empty_bit(entry);
/* bit -> addr */
- addr = (i * cmsfs.blksize * 8 + cmsfs.blksize * bit)
- + (block_nr * BYTES_PER_BLOCK);
+ addr = ((off_t) cmsfs.blksize * i * 8 +
+ (off_t) cmsfs.blksize * bit) +
+ (off_t) block_nr * BYTES_PER_BLOCK;
amap_block_set(addr);
return addr;
}
--- a/cmsfs-fuse/cmsfs-fuse.c
+++ b/cmsfs-fuse/cmsfs-fuse.c
@@ -162,7 +162,7 @@ struct file;
struct file_operations {
int (*cache_data) (struct file *f, off_t addr, int level, int *block,
- unsigned int *disp, int *record, size_t *total);
+ unsigned int *disp, int *record, off_t *total);
int (*write_data) (struct file *f, const char *buf, int len, size_t size,
int rlen);
int (*delete_pointers) (struct file *f, int level, off_t addr);
@@ -197,7 +197,7 @@ struct file {
/* disk address of next byte to write */
off_t write_ptr;
/* the filesize while the file is opened */
- ssize_t session_size;
+ off_t session_size;
/* number of null blocks for fixed files */
int nr_null_blocks;
/* number of written padding bytes for a fixed file */
@@ -312,7 +312,7 @@ int _read(void *buf, size_t size, off_t
(addr & ~DATA_BLOCK_MASK))
DIE("read: crossing blocks addr: %lx size: %ld\n",
addr, size);
- if ((addr < cmsfs.fdir) || ((size_t) addr > cmsfs.size))
+ if (addr < cmsfs.fdir || addr > cmsfs.size)
return -EIO;
memcpy(buf, cmsfs.map + addr, size);
@@ -326,7 +326,7 @@ int _write(const void *buf, size_t size,
DIE("write: crossing blocks addr: %x size: %d\n",
(int)addr, (int)size);
- if ((addr < (2 * cmsfs.blksize)) || ((size_t) addr > cmsfs.size))
+ if ((addr < (2 * cmsfs.blksize)) || (addr > cmsfs.size))
return -EIO;
if (buf == NULL)
@@ -745,7 +745,7 @@ static int edf_name_valid(const char *na
/*
* Summarize the number of bytes used in the last data block.
*/
-static int walk_last_var_data_block(off_t addr, ssize_t *total)
+static int walk_last_var_data_block(off_t addr, off_t *total)
{
ssize_t left = cmsfs.blksize;
u16 len;
@@ -837,7 +837,7 @@ static void set_record_len(struct file *
}
static void set_record(struct file *f, int *record, off_t addr, int len,
- size_t *total, int block)
+ off_t *total, int block)
{
struct record *r = &f->rlist[*record];
@@ -917,10 +917,10 @@ static void set_record_extension(struct
}
/* check for file end via byte count and return count of bytes left */
-static size_t crop_file_end(struct file *f, int record, size_t done,
+static int crop_file_end(struct file *f, int record, off_t done,
int first)
{
- size_t filesize = f->fst->nr_records * f->fst->record_len;
+ off_t filesize = (off_t) f->fst->nr_records * (off_t) f->fst->record_len;
struct record *rec = &f->rlist[record];
struct record_ext *rext = rec->ext;
@@ -951,9 +951,9 @@ static int end_of_file(struct file *f, i
}
static void walk_fixed_data_block(struct file *f, off_t addr, int *record,
- size_t *total, int block, int disp)
+ off_t *total, int block, int disp)
{
- off_t offset = block * cmsfs.blksize + disp;
+ off_t offset = (off_t ) block * cmsfs.blksize + disp;
int rlen = (f->fst->record_len > cmsfs.blksize) ?
cmsfs.blksize : f->fst->record_len;
int first = (offset % f->fst->record_len) ?
@@ -1024,7 +1024,7 @@ out:
}
static int walk_var_data_block(struct file *f, off_t addr, unsigned int disp,
- int *record, size_t *total, int block, int skip)
+ int *record, off_t *total, int block, int skip)
{
ssize_t left = cmsfs.blksize - skip;
int last, rc;
@@ -1159,7 +1159,7 @@ static int walk_var_data_block(struct fi
}
static void cache_fixed_data_block(struct file *f, off_t addr, int *block,
- int *record, size_t *total, int disp)
+ int *record, off_t *total, int disp)
{
/*
* Cannot distinguish null block pointers from not existing pointers,
@@ -1180,7 +1180,7 @@ static void cache_fixed_data_block(struc
* data block respecting the sequence of the data.
*/
static int cache_file_fixed(struct file *f, off_t addr, int level, int *block,
- unsigned int *disp, int *record, size_t *total)
+ unsigned int *disp, int *record, off_t *total)
{
int left = f->ptr_per_block;
off_t ptr;
@@ -1203,7 +1203,7 @@ static int cache_file_fixed(struct file
}
static int cache_variable_data_block(struct file *f, off_t addr, int *block,
- int *record, int disp, size_t *total, int skip)
+ int *record, int disp, off_t *total, int skip)
{
int rc;
@@ -1234,7 +1234,7 @@ static int cache_variable_data_block(str
*/
static int cache_file_variable(struct file *f, off_t addr, int level,
int *block, unsigned int *disp,
- int *record, size_t *total)
+ int *record, off_t *total)
{
int nr, left = f->ptr_per_block;
off_t ptr;
@@ -1570,7 +1570,7 @@ static int cache_file(struct file *f)
{
int block = 0, record = -1;
unsigned int disp = 0;
- size_t total = 0;
+ off_t total = 0;
return f->fops->cache_data(f, ABS(f->fst->fop), f->fst->levels,
&block, &disp, &record, &total);
@@ -1588,22 +1588,23 @@ static void workaround_nr_blocks(struct
if (f->fst->record_format == RECORD_LEN_VARIABLE)
return;
- nr = f->fst->nr_records * f->fst->record_len / cmsfs.blksize;
- if (f->fst->nr_records * f->fst->record_len % cmsfs.blksize)
+ nr = (off_t) f->fst->nr_records * (off_t) f->fst->record_len
+ / cmsfs.blksize;
+ if ((off_t) f->fst->nr_records * (off_t) f->fst->record_len % cmsfs.blksize)
nr++;
f->nr_null_blocks = nr - f->fst->nr_blocks;
f->fst->nr_blocks = nr;
}
-static ssize_t get_file_size_fixed(struct fst_entry *fst)
+static off_t get_file_size_fixed(struct fst_entry *fst)
{
- return fst->nr_records * fst->record_len;
+ return (off_t) fst->nr_records * (off_t) fst->record_len;
}
-static ssize_t get_file_size_variable(struct fst_entry *fst)
+static off_t get_file_size_variable(struct fst_entry *fst)
{
struct var_ptr vptr;
- ssize_t total = 0;
+ off_t total = 0;
off_t ptr;
int rc;
@@ -1643,7 +1644,7 @@ skip_scan:
* also null blocks.
*/
if (fst->nr_blocks)
- total += (fst->nr_blocks - 1) * cmsfs.blksize;
+ total += ((off_t) fst->nr_blocks - 1) * cmsfs.blksize;
return total;
}
@@ -1651,7 +1652,7 @@ skip_scan:
* Return the file size as it is on the disk. Includes headers for
* variable records.
*/
-static ssize_t get_file_size(struct fst_entry *fst)
+static off_t get_file_size(struct fst_entry *fst)
{
if (fst->record_format == RECORD_LEN_FIXED)
return get_file_size_fixed(fst);
@@ -1660,9 +1661,9 @@ static ssize_t get_file_size(struct fst_
return 0;
}
-static ssize_t get_file_size_logical(struct fst_entry *fst)
+static off_t get_file_size_logical(struct fst_entry *fst)
{
- ssize_t total;
+ off_t total;
if (fst->nr_records == 0)
return 0;
@@ -1674,7 +1675,7 @@ static ssize_t get_file_size_logical(str
/* subtract the record headers */
if (fst->record_format == RECORD_LEN_VARIABLE)
- total -= fst->nr_records * VAR_RECORD_HEADER_SIZE;
+ total -= (off_t) fst->nr_records * VAR_RECORD_HEADER_SIZE;
if (linefeed_mode_enabled(fst))
total += fst->nr_records;
@@ -1707,7 +1708,7 @@ static int cmsfs_getattr(const char *pat
stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime;
/* size */
- stbuf->st_size = fst.record_len * fst.nr_records;
+ stbuf->st_size = (off_t) fst.record_len * (off_t) fst.nr_records;
stbuf->st_blocks = max(stbuf->st_size, cmsfs.blksize);
stbuf->st_blocks = ((stbuf->st_blocks + cmsfs.data_block_mask) &
~cmsfs.data_block_mask) >> 9;
@@ -1730,7 +1731,7 @@ static int cmsfs_getattr(const char *pat
* Include potential sparse blocks for variable files which
* are included in nr_blocks to avoid scanning the whole file.
*/
- stbuf->st_blocks = fst.nr_blocks * cmsfs.nr_blocks_512;
+ stbuf->st_blocks = (off_t) fst.nr_blocks * cmsfs.nr_blocks_512;
}
return 0;
}
@@ -2598,16 +2599,21 @@ static int cmsfs_statfs(const char *path
{
unsigned int inode_size = cmsfs.blksize + sizeof(struct fst_entry);
unsigned int free_blocks = cmsfs.total_blocks - cmsfs.used_blocks;
+ unsigned long long tmp;
(void) path;
buf->f_bsize = buf->f_frsize = cmsfs.blksize;
buf->f_blocks = cmsfs.total_blocks;
buf->f_bfree = buf->f_bavail = free_blocks;
+
/* number of possible inodes */
- buf->f_files = cmsfs.total_blocks * cmsfs.blksize / inode_size;
+ tmp = (unsigned long long) cmsfs.total_blocks *
+ cmsfs.blksize / inode_size;
+ buf->f_files = (long) tmp;
- buf->f_ffree = free_blocks * cmsfs.blksize / inode_size;
+ tmp = (unsigned long long) free_blocks * cmsfs.blksize / inode_size;
+ buf->f_ffree = (long) tmp;
buf->f_namemax = MAX_FNAME - 1;
return 0;
}
@@ -3163,9 +3169,8 @@ static void update_fst(struct file *f, o
static int cmsfs_truncate(const char *path, off_t size)
{
struct fst_entry fst;
- off_t fst_addr;
+ off_t fst_addr, len;
struct file *f;
- ssize_t len;
int rc = 0;
if (cmsfs.readonly)
@@ -3715,7 +3720,7 @@ static void delete_record(struct file *f
static int update_records(struct file *f, int nrecords)
{
int i, rc, rnr, bnr = 0, skip = 0;
- size_t total = 0;
+ off_t total = 0;
rnr = f->fst->nr_records - 1;
if (rnr >= 0) {
@@ -3812,7 +3817,7 @@ static int new_blocks(struct file *f, si
return 0;
if (f->fst->record_format == RECORD_LEN_VARIABLE)
- tmp += nrecords * VAR_RECORD_HEADER_SIZE;
+ tmp += (double) nrecords * VAR_RECORD_HEADER_SIZE;
tmp -= last;
if (tmp <= 0)
@@ -3981,7 +3986,7 @@ out:
static int do_write(struct file *f, const char *buf, size_t size, off_t offset)
{
- ssize_t len, copied = 0;
+ off_t len, copied = 0;
struct var_ptr vptr;
int rc;
--- a/cmsfs-fuse/cmsfs-fuse.h
+++ b/cmsfs-fuse/cmsfs-fuse.h
@@ -18,7 +18,7 @@
extern struct cmsfs cmsfs;
/* conversion between absolute and relative addresses */
-#define ABS(x) ((x - 1) * cmsfs.blksize)
+#define ABS(x) ((off_t) (x - 1) * cmsfs.blksize)
#define REL(x) ((x / cmsfs.blksize) + 1)
struct fcache_entry {
@@ -45,7 +45,7 @@ struct cmsfs {
/* start of mmap of the whole block device */
char *map;
/* size of the disk */
- size_t size;
+ off_t size;
/* formatted blocksize */
int blksize;
/* number of 512 byte blocks per block */
@@ -86,7 +86,7 @@ struct cmsfs {
int bits_per_data_block;
int bits_per_ptr_block;
int data_block_mask;
- int amap_bytes_per_block;
+ off_t amap_bytes_per_block;
/* file cache */
struct fcache_entry *fcache;
--- a/cmsfs-fuse/edf.h
+++ b/cmsfs-fuse/edf.h
@@ -27,7 +27,7 @@ struct fst_entry {
int record_len;
char res3[4];
- int fop;
+ unsigned int fop;
/* number of data blocks (not incl. pointer blocks) */
int nr_blocks;
int nr_records;