From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55266) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a1ZfM-0004Ny-JH for qemu-devel@nongnu.org; Wed, 25 Nov 2015 07:59:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1a1ZfL-0001J8-24 for qemu-devel@nongnu.org; Wed, 25 Nov 2015 07:59:20 -0500 Received: from mx1.redhat.com ([209.132.183.28]:52670) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1a1ZfK-0001J3-Ql for qemu-devel@nongnu.org; Wed, 25 Nov 2015 07:59:18 -0500 From: marcandre.lureau@redhat.com Date: Wed, 25 Nov 2015 13:59:11 +0100 Message-Id: <1448456352-14143-2-git-send-email-marcandre.lureau@redhat.com> In-Reply-To: <1448456352-14143-1-git-send-email-marcandre.lureau@redhat.com> References: <1448456352-14143-1-git-send-email-marcandre.lureau@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH v3 1/2] qga: flush explicitly when needed List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , mdroth@linux.vnet.ibm.com From: Marc-Andr=C3=A9 Lureau According to the specification: http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html "the application shall ensure that output is not directly followed by input without an intervening call to fflush() or to a file positioning function (fseek(), fsetpos(), or rewind()), and input is not directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file." Without this change, a write() followed by a read() may lose the previously written content, as shown in the following test. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=3D1210246 --- qga/commands-posix.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 0ebd473..cf1d7ec 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -216,9 +216,16 @@ void qmp_guest_set_time(bool has_time, int64_t time_= ns, Error **errp) } } =20 +typedef enum { + RW_STATE_NEW, + RW_STATE_READING, + RW_STATE_WRITING, +} RwState; + typedef struct GuestFileHandle { uint64_t id; FILE *fh; + RwState state; QTAILQ_ENTRY(GuestFileHandle) next; } GuestFileHandle; =20 @@ -460,6 +467,17 @@ struct GuestFileRead *qmp_guest_file_read(int64_t ha= ndle, bool has_count, } =20 fh =3D gfh->fh; + + /* explicitly flush when switching from writing to reading */ + if (gfh->state =3D=3D RW_STATE_WRITING) { + int ret =3D fflush(fh); + if (ret =3D=3D EOF) { + error_setg_errno(errp, errno, "failed to flush file"); + return NULL; + } + gfh->state =3D RW_STATE_NEW; + } + buf =3D g_malloc0(count+1); read_count =3D fread(buf, 1, count, fh); if (ferror(fh)) { @@ -473,6 +491,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t han= dle, bool has_count, if (read_count) { read_data->buf_b64 =3D g_base64_encode(buf, read_count); } + gfh->state =3D RW_STATE_READING; } g_free(buf); clearerr(fh); @@ -496,6 +515,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle,= const char *buf_b64, } =20 fh =3D gfh->fh; + + if (gfh->state =3D=3D RW_STATE_READING) { + int ret =3D fseek(fh, 0, SEEK_CUR); + if (ret =3D=3D -1) { + error_setg_errno(errp, errno, "failed to seek file"); + return NULL; + } + gfh->state =3D RW_STATE_NEW; + } + buf =3D g_base64_decode(buf_b64, &buf_len); =20 if (!has_count) { @@ -515,6 +544,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, = const char *buf_b64, write_data =3D g_new0(GuestFileWrite, 1); write_data->count =3D write_count; write_data->eof =3D feof(fh); + gfh->state =3D RW_STATE_WRITING; } g_free(buf); clearerr(fh); @@ -538,10 +568,15 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t h= andle, int64_t offset, ret =3D fseek(fh, offset, whence); if (ret =3D=3D -1) { error_setg_errno(errp, errno, "failed to seek file"); + if (errno =3D=3D ESPIPE) { + /* file is non-seekable, stdio shouldn't be buffering anyway= s */ + gfh->state =3D RW_STATE_NEW; + } } else { seek_data =3D g_new0(GuestFileSeek, 1); seek_data->position =3D ftell(fh); seek_data->eof =3D feof(fh); + gfh->state =3D RW_STATE_NEW; } clearerr(fh); =20 @@ -562,6 +597,8 @@ void qmp_guest_file_flush(int64_t handle, Error **err= p) ret =3D fflush(fh); if (ret =3D=3D EOF) { error_setg_errno(errp, errno, "failed to flush file"); + } else { + gfh->state =3D RW_STATE_NEW; } } =20 --=20 2.5.0