On 19.08.19 18:18, Denis Plotnikov wrote: > The patch allows to provide a pattern file for write > command. There was no similar ability before. > > Signed-off-by: Denis Plotnikov > --- > v9: > * replace flag cast to int with bool [Eric] > * fix the error message [Eric] > * use qemu_io_free instead of qemu_vfree [Eric] > * add function description [Eric] > > v8: fix according to Max's comments > * get rid of unnecessary buffer for the pattern > * buffer allocation just in bytes > * take into account the missalign offset > * don't copy file name > * changed char* to const char* in input params > > v7: > * fix variable naming > * make code more readable > * extend help for write command > > v6: > * the pattern file is read once to reduce io > > v5: > * file name initiated with null to make compilers happy > > v4: > * missing signed-off clause added > > v3: > * missing file closing added > * exclusive flags processing changed > * buffer void* converted to char* to fix pointer arithmetics > * file reading error processing added > --- > qemu-io-cmds.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 91 insertions(+), 6 deletions(-) > > diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c > index 09750a23ce..f7bdfe673b 100644 > --- a/qemu-io-cmds.c > +++ b/qemu-io-cmds.c > @@ -351,6 +351,77 @@ static void qemu_io_free(void *p) > qemu_vfree(p); > } > > +/* > + * qemu_io_alloc_from_file() > + * > + * Allocates the buffer and populates it with the content of the given file > + * up to @len bytes. If the file length is less then @len, then the buffer s/then/than/ (the first one) > + * is populated with then file content cyclically. s/then/the/ > + * > + * @blk - the block backend where the buffer content is going to be written to > + * @len - the buffer length > + * @file_name - the file to copy the content from Probably better s/copy/read/ > + * > + * Returns: the buffer pointer on success > + * NULL on error > + */ > +static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len, > + const char *file_name) > +{ > + char *buf, *buf_origin; > + FILE *f = fopen(file_name, "r"); > + int pattern_len; > + > + if (!f) { > + perror(file_name); > + return NULL; > + } > + > + if (qemuio_misalign) { > + len += MISALIGN_OFFSET; > + } > + > + buf_origin = buf = blk_blockalign(blk, len); > + > + if (qemuio_misalign) { > + buf_origin += MISALIGN_OFFSET; > + } > + > + pattern_len = fread(buf_origin, 1, len, f); Pulling the misalignment up here has more effects than just requiring qemu_io_free() rather than qemu_vfree(). First, it breaks this fread(), because @len is the length of the buffer in total, so this here is a buffer overflow. > + > + if (ferror(f)) { > + perror(file_name); > + goto error; > + } > + > + if (pattern_len == 0) { > + fprintf(stderr, "%s: file is empty\n", file_name); > + goto error; > + } > + > + fclose(f); > + > + if (len > pattern_len) { > + len -= pattern_len; > + buf += pattern_len; > + > + while (len > 0) { > + size_t len_to_copy = MIN(pattern_len, len); > + > + memcpy(buf, buf_origin, len_to_copy); Second, it breaks this memcpy(), because now [buf, buf + len_to_copy) and [buf_origin, buf_origin + len_to_copy) may overlap. I think the solution would be (1) to add MISALIGN_OFFSET not only to @buf_origin, but to @buf also, and (2) to reduce len by MISALIGN_OFFSET. So all in all, I think both issues should be fixed if you add “buf += MISALIGN_OFFSET” and “len -= MISALIGN_OFFSET” to the second “if (qemuio_misalign)” block. I think. > + > + len -= len_to_copy; > + buf += len_to_copy; > + } > + } > + > + return buf_origin; > + > +error: > + qemu_io_free(buf_origin); > + return NULL; > +} > + > static void dump_buffer(const void *buffer, int64_t offset, int64_t len) > { > uint64_t i; [...] > @@ -1051,8 +1128,9 @@ static int write_f(BlockBackend *blk, int argc, char **argv) > return -EINVAL; > } > > - if (zflag && Pflag) { > - printf("-z and -P cannot be specified at the same time\n"); > + if ((bool)zflag + (bool)Pflag + (bool)sflag > 1) { Eric’s point was that you don’t need to cast at all. Max > + printf("Only one of -z, -P, and -s " > + "can be specified at the same time\n"); > return -EINVAL; > } >