Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.2
s390-tools
s390-tools-sles11sp2-cmsfs-fuse-eof.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles11sp2-cmsfs-fuse-eof.patch of Package s390-tools
Description: cmsfs-fuse: Fix EOF detection for fixed record format files Symptom: Reading a file fails with -EIO. Problem: For reading a file cmsfs-fuse must parse the record data. This record data is calculated on-the-fly for fixed record format files. The calculation of the remainder of a fixed record on a new block can be wrong. Solution: Fix the calculation and make the detection of the file end more robust. Problem-ID: 75940 --- cmsfs-fuse/cmsfs-fuse.c | 96 +++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 54 deletions(-) --- a/cmsfs-fuse/cmsfs-fuse.c +++ b/cmsfs-fuse/cmsfs-fuse.c @@ -920,87 +920,66 @@ static void set_record_extension(struct f->record_scan_state = RSS_DATA_BLOCK_EXT; } -/* check for file end via byte count and return count of bytes left */ -static int crop_file_end(struct file *f, int record, off_t done, - int first) -{ - 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; - - /* done already includes the complete record length incl. extensions */ - done -= rec->total_len; - /* remove possible linefeeds before comparing with on-disk file size */ - if (f->linefeed && record) - done -= record; - done += rec->first_block_len; - - /* add length of all existing extensions */ - while (rext != NULL) { - done += rext->len; - rext = rext->next; - } - - if (done + first > filesize) - first = filesize - done; - return first; -} - /* check for file end by record number */ static int end_of_file(struct file *f, int record) { - if (record == f->fst->nr_records) + if (record == f->fst->nr_records - 1) return 1; return 0; } -static void walk_fixed_data_block(struct file *f, off_t addr, int *record, +static int walk_fixed_data_block(struct file *f, off_t addr, int *record, off_t *total, int block, int disp) { off_t offset = (off_t ) block * cmsfs.blksize + disp; - int rlen = (f->fst->record_len > cmsfs.blksize) ? + int len = (f->fst->record_len > cmsfs.blksize) ? cmsfs.blksize : f->fst->record_len; - int first = (offset % f->fst->record_len) ? - rlen - (offset % rlen) : 0; int left = cmsfs.blksize - disp; + int first = 0; + + if (offset % f->fst->record_len) { + if (f->fst->record_len - offset >= cmsfs.blksize) + first = cmsfs.blksize; + else + first = (f->fst->record_len % cmsfs.blksize) - (offset % len); + } if (first) { BUG(first > left); - - first = crop_file_end(f, *record, *total, first); set_record_extension(f, record, addr, first, block); left -= first; if (addr != NULL_BLOCK) addr += first; } - while (left >= rlen) { + while (left >= len) { /* * Increment record number only after adding a possible * extension. *record starts with -1 so the first is 0. */ - (*record)++; if (end_of_file(f, *record)) - return; + return 1; + (*record)++; set_record_len(f, *record, f->fst->record_len); - set_record(f, record, addr, rlen, total, block); + set_record(f, record, addr, len, total, block); - left -= rlen; + left -= len; if (addr != NULL_BLOCK) - addr += rlen; + addr += len; } /* partial record left */ if (left > 0) { - (*record)++; if (end_of_file(f, *record)) - return; + return 1; + (*record)++; set_record_len(f, *record, f->fst->record_len); set_record(f, record, addr, left, total, block); - return; + return 0; } + return 0; } static int get_record_unused_bytes(struct file *f, int nr) @@ -1150,7 +1129,7 @@ static int walk_var_data_block(struct fi /* split header */ if (left == 1) { - if (end_of_file(f, *record + 1)) + if (end_of_file(f, *record)) return 0; rc = _read(&half_len, sizeof(half_len), addr); if (rc < 0) @@ -1162,21 +1141,23 @@ static int walk_var_data_block(struct fi return 0; } -static void cache_fixed_data_block(struct file *f, off_t addr, int *block, - int *record, off_t *total, int disp) +static int cache_fixed_data_block(struct file *f, off_t addr, int *block, + int *record, off_t *total, int disp) { /* * Cannot distinguish null block pointers from not existing pointers, * so this fn is called for the whole pointer block and maybe for * non-existing blocks and records too. Check and bail out if EOF. */ - if (*block >= f->fst->nr_blocks) - return; + if (*block >= f->fst->nr_blocks || *record >= f->fst->nr_records) + return 0; - walk_fixed_data_block(f, addr, record, total, *block, disp); f->blist[*block].disk_addr = addr & ~DATA_BLOCK_MASK; + walk_fixed_data_block(f, addr, record, total, *block, disp); + /* record starts with 0 but on-disk record number with 1 */ f->blist[*block].hi_record_nr = *record + 1; (*block)++; + return 0; } /* @@ -1184,7 +1165,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, off_t *total) + unsigned int *disp, int *record, off_t *total) { int left = f->ptr_per_block; off_t ptr; @@ -1195,6 +1176,15 @@ static int cache_file_fixed(struct file ptr = get_fixed_pointer(addr); if (ptr < 0) return ptr; + /* + * In difference to variable record format a null pointer + * may be valid for a null block so we cannot determine + * the file end from a pointer entry. Check for the number + * of scanned blocks instead. + */ + if (*block >= f->fst->nr_blocks + || *record >= f->fst->nr_records) + return 0; cache_file_fixed(f, ptr, level, block, disp, record, total); /* don't increment for null block pointers */ if (addr) @@ -1202,8 +1192,7 @@ static int cache_file_fixed(struct file } return 0; } - cache_fixed_data_block(f, addr, block, record, total, 0); - return 0; + return cache_fixed_data_block(f, addr, block, record, total, 0); } static int cache_variable_data_block(struct file *f, off_t addr, int *block, @@ -1216,15 +1205,14 @@ static int cache_variable_data_block(str * so this fn is called for the whole pointer block and maybe for * non-existing blocks and records too. Check and bail out if EOF. */ - if (*block >= f->fst->nr_blocks || - *record >= f->fst->nr_records) + if (*block >= f->fst->nr_blocks || *record >= f->fst->nr_records) return 0; + f->blist[*block].disk_addr = addr & ~DATA_BLOCK_MASK; rc = walk_var_data_block(f, addr, disp, record, total, *block, skip); if (rc < 0) return rc; - f->blist[*block].disk_addr = addr & ~DATA_BLOCK_MASK; /* record starts with 0 but on-disk record number with 1 */ f->blist[*block].hi_record_nr = *record + 1; f->blist[*block].disp = disp;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor