Signed-off-by: Claudio Fontana <cfontana(a)suse.de>
---
src/util/iohelper.c | 17 +---------
src/util/virfile.c | 82 ++++++++++++++++++++++++++++++++++-----------
src/util/virfile.h | 2 +-
3 files changed, 64 insertions(+), 37 deletions(-)
diff --git a/src/util/iohelper.c b/src/util/iohelper.c
index ce10ccb905..055540c8c4 100644
--- a/src/util/iohelper.c
+++ b/src/util/iohelper.c
@@ -58,7 +58,6 @@ int
main(int argc, char **argv)
{
const char *path;
- int oflags = -1;
int fd = -1;
program_name = argv[0];
@@ -79,25 +78,11 @@ main(int argc, char **argv)
program_name, argv[3]);
exit(EXIT_FAILURE);
}
-#ifdef F_GETFL
- oflags = fcntl(fd, F_GETFL);
-#else
- /* Stupid mingw. */
- if (fd == STDIN_FILENO)
- oflags = O_RDONLY;
- else if (fd == STDOUT_FILENO)
- oflags = O_WRONLY;
-#endif
- if (oflags < 0) {
- fprintf(stderr, _("%s: unable to determine access mode of fd %d"),
- program_name, fd);
- exit(EXIT_FAILURE);
- }
} else { /* unknown argc pattern */
usage(EXIT_FAILURE);
}
- if (fd < 0 || virFileDiskCopy(path, fd, oflags) < 0)
+ if (fd < 0 || virFileDiskCopy(fd, path, -1, "stdio") < 0)
goto error;
return 0;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 30b0eee074..87d3e53819 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -4669,19 +4669,64 @@ runIOCopy(const struct runIOParams p)
return total;
}
+/**
+ * virFileDiskCopy: run IO to copy data between storage and a pipe or socket.
+ *
+ * @disk_fd: the already open regular file or block device
+ * @disk_path: the pathname corresponding to disk_fd (for error reporting)
+ * @remote_fd: the pipe or socket
+ * Use -1 to auto-choose between STDIN or STDOUT.
+ * @remote_path: the pathname corresponding to remote_fd (for error reporting)
+ *
+ * Note that the direction of the transfer is detected based on the @disk_fd
+ * file access mode (man 2 open). Therefore @disk_fd must be opened with
+ * O_RDONLY or O_WRONLY. O_RDWR is not supported.
+ *
+ * virFileDiskCopy always closes the file descriptor disk_fd,
+ * and any error during close(2) is reported and considered a failure.
+ *
+ * Returns: bytes transferred or < 0 on failure.
+ */
off_t
-virFileDiskCopy(const char *path, int fd, int oflags)
+virFileDiskCopy(int disk_fd, const char *disk_path, int remote_fd, const char
*remote_path)
{
int ret = -1;
off_t total = 0;
struct stat sb;
struct runIOParams p;
+ int oflags = -1;
+
+#ifdef F_GETFL
+ oflags = fcntl(disk_fd, F_GETFL);
+#else /* !F_GETFL */
+ /*
+ * mingw still does not support F_GETFL, and does not seem willing to
+ * support it in the future. So we need a hack to get iohelper working,
+ * specifically possible only when using stdio.
+ */
+ if (disk_fd == STDIN_FILENO) {
+ oflags = O_RDONLY;
+ } else if (disk_fd == STDOUT_FILENO) {
+ oflags = O_WRONLY;
+ } else {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+ _("%s: disk_fd must be stdin or stdout, due to lack of
F_GETFL (mingw)"),
+ __FUNCTION__);
+ goto cleanup;
+ }
+#endif /* !F_GETFL */
- if (fstat(fd, &sb) < 0) {
+ if (oflags < 0) {
virReportSystemError(errno,
- _("Unable to access file descriptor %d path %s"),
- fd, path);
+ _("unable to determine access mode of %s"),
+ disk_path);
+ goto cleanup;
+ }
+ if (fstat(disk_fd, &sb) < 0) {
+ virReportSystemError(errno,
+ _("unable to stat file descriptor %d path %s"),
+ disk_fd, disk_path);
goto cleanup;
}
p.isBlockDev = S_ISBLK(sb.st_mode);
@@ -4690,23 +4735,21 @@ virFileDiskCopy(const char *path, int fd, int oflags)
switch (oflags & O_ACCMODE) {
case O_RDONLY:
p.isWrite = false;
- p.fdin = fd;
- p.fdinname = path;
- p.fdout = STDOUT_FILENO;
- p.fdoutname = "stdout";
+ p.fdin = disk_fd;
+ p.fdinname = disk_path;
+ p.fdout = remote_fd >= 0 ? remote_fd : STDOUT_FILENO;
+ p.fdoutname = remote_path;
break;
case O_WRONLY:
p.isWrite = true;
- p.fdin = STDIN_FILENO;
- p.fdinname = "stdin";
- p.fdout = fd;
- p.fdoutname = path;
+ p.fdin = remote_fd >= 0 ? remote_fd : STDIN_FILENO;
+ p.fdinname = remote_path;
+ p.fdout = disk_fd;
+ p.fdoutname = disk_path;
break;
-
case O_RDWR:
default:
- virReportSystemError(EINVAL,
- _("Unable to process file with flags %d"),
+ virReportSystemError(EINVAL, _("Unable to process file with flags
%d"),
(oflags & O_ACCMODE));
goto cleanup;
}
@@ -4715,12 +4758,12 @@ virFileDiskCopy(const char *path, int fd, int oflags)
if (!p.isBlockDev && p.isDirect) {
off_t off;
if (p.isWrite) {
- if ((off = lseek(fd, 0, SEEK_END)) != 0) {
+ if ((off = lseek(disk_fd, 0, SEEK_END)) != 0) {
virReportSystemError(off < 0 ? errno : EINVAL, "%s",
_("O_DIRECT write needs empty seekable
file"));
goto cleanup;
}
- } else if ((off = lseek(fd, 0, SEEK_CUR)) != 0) {
+ } else if ((off = lseek(disk_fd, 0, SEEK_CUR)) != 0) {
virReportSystemError(off < 0 ? errno : EINVAL, "%s",
_("O_DIRECT read needs entire seekable
file"));
goto cleanup;
@@ -4742,9 +4785,8 @@ virFileDiskCopy(const char *path, int fd, int oflags)
ret = 0;
cleanup:
- if (VIR_CLOSE(fd) < 0 &&
- ret == 0) {
- virReportSystemError(errno, _("Unable to close %s"), path);
+ if (VIR_CLOSE(disk_fd) < 0 && ret == 0) {
+ virReportSystemError(errno, _("Unable to close %s"), disk_path);
ret = -1;
}
return ret;
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 59efb760f3..8e378efe30 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -384,4 +384,4 @@ int virFileDataSync(int fd);
int virFileSetCOW(const char *path,
virTristateBool state);
-off_t virFileDiskCopy(const char *path, int fd, int oflags);
+off_t virFileDiskCopy(int disk_fd, const char *disk_path, int remote_fd, const char
*remote_path);
--
2.34.1