cmsfs-fuse: Fix iconv buffer aliasing

GCC8 shows the following compile warning:

cmsfs-fuse.c: In function ‘convert_text’:
cmsfs-fuse.c:2558:19: warning: passing argument 2 to restrict-qualified
parameter aliases with argument 4 [-Wrestrict]
  rc = iconv(conv, &data_ptr, &in_count, &data_ptr, &out_count);
                   ^~~~~~~~~             ~~~~~~~~~

Fix this by using a separate buffer for iconv. The buffer size depends on
the record format: variable-length records have a maximum length of
MAX_RECORD_LEN (plus 1 byte for linefeed), while fixed-length records
could be larger in theory. This patch takes that into account for the iconv
buffer, but the rest of the code currently cannot handle fixed-length records
larger than MAX_RECORD_LEN.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Gerald Schaefer
2018-12-11 19:33:24 +01:00
committed by Jan Höppner
parent 4d008849f7
commit 6f7cb68dcf
2 changed files with 43 additions and 13 deletions

View File

@@ -1,5 +1,12 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.x.x (xxxx-xx-xx)__
For Linux kernel version: 4.xx
Bug Fixes:
- cmfs-fuse: Fix iconv buffer aliasing
* __v2.7.0 (2018-10-31)__
For Linux kernel version: 4.19

View File

@@ -233,6 +233,8 @@ struct file {
int null_records;
/* write cache for text mode */
char *wcache;
/* buffer for iconv */
char *iconv_buf;
/* used bytes in write cache */
int wcache_used;
/* committed written bytes to FUSE */
@@ -1849,6 +1851,25 @@ static int cmsfs_open(const char *path, struct fuse_file_info *fi)
if (f->wcache == NULL)
return -ENOMEM;
/*
* For fixed-length records f->fst->record_len contains
* the fixed record length, which will not change. For
* variable-length records it contains the (current) maximum
* record length, which could be increased later by appending
* new records, so use MAX_RECORD_LEN for the iconv buffer.
* The MAX_RECORD_LEN is not valid for fixed-length records,
* only for variable-length records, so use the actual record
* length (f->fst->record_len) for fixed-length records.
*/
if (f->fst->record_format == RECORD_LEN_FIXED)
f->iconv_buf = malloc(f->fst->record_len + 1);
else
f->iconv_buf = malloc(MAX_RECORD_LEN + 1);
if (f->iconv_buf == NULL) {
destroy_file_object(f);
return -ENOMEM;
}
util_strlcpy(f->path, path, MAX_FNAME + 1);
str_toupper(f->path);
@@ -2548,14 +2569,13 @@ static void get_block_data_from_record(struct record *rec, off_t offset,
}
}
static int convert_text(iconv_t conv, char *buf, int size)
static int convert_text(iconv_t conv, char *in_buf, char *out_buf, int size)
{
size_t out_count = size;
size_t in_count = size;
char *data_ptr = buf;
int rc;
rc = iconv(conv, &data_ptr, &in_count, &data_ptr, &out_count);
rc = iconv(conv, &in_buf, &in_count, &out_buf, &out_count);
if ((rc == -1) || (in_count != 0)) {
DEBUG("Code page translation EBCDIC-ASCII failed\n");
return -EIO;
@@ -2616,14 +2636,15 @@ static int cmsfs_read(const char *path, char *buf, size_t size, off_t offset,
/* read one record */
if (addr == NULL_BLOCK)
memset(buf, 0, chunk);
else {
rc = _read(buf, chunk, addr);
else if (f->translate) {
rc = _read(f->iconv_buf, chunk, addr);
if (rc < 0)
return rc;
}
if (f->translate) {
rc = convert_text(cmsfs.iconv_from, buf, chunk);
rc = convert_text(cmsfs.iconv_from, f->iconv_buf, buf, chunk);
if (rc < 0)
return rc;
} else {
rc = _read(buf, chunk, addr);
if (rc < 0)
return rc;
}
@@ -4221,7 +4242,7 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
}
/* translate */
rc = convert_text(cmsfs.iconv_to, f->wcache, f->wcache_used);
rc = convert_text(cmsfs.iconv_to, f->wcache, f->iconv_buf, f->wcache_used);
if (rc < 0)
return rc;
@@ -4231,6 +4252,7 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
*/
if (!f->wcache_used) {
*f->wcache = FILLER_EBCDIC;
*f->iconv_buf = FILLER_EBCDIC;
f->wcache_used = 1;
nl_byte = 0;
null_record = 1;
@@ -4241,7 +4263,7 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
offset += f->pad_bytes;
BUG(offset < 0);
rc = do_write(f, f->wcache, f->wcache_used, offset);
rc = do_write(f, f->iconv_buf, f->wcache_used, offset);
if (rc < 0)
return rc;
@@ -4283,7 +4305,7 @@ static int flush_wcache(struct file *f)
int rc;
/* translate */
rc = convert_text(cmsfs.iconv_to, f->wcache, f->wcache_used);
rc = convert_text(cmsfs.iconv_to, f->wcache, f->iconv_buf, f->wcache_used);
if (rc < 0)
return rc;
@@ -4291,7 +4313,7 @@ static int flush_wcache(struct file *f)
offset -= (f->fst->nr_records - f->null_records);
BUG(offset < 0);
rc = do_write(f, f->wcache, f->wcache_used, offset);
rc = do_write(f, f->iconv_buf, f->wcache_used, offset);
purge_wcache(f);
f->null_records = 0;
if (rc < 0)
@@ -4414,6 +4436,7 @@ static void destroy_file_object(struct file *f)
struct record *rec;
int i;
free(f->iconv_buf);
free(f->wcache);
free(f->wstate);