]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virfile: change virFileDiskCopy arguments to extend beyond stdin, stdout
authorClaudio Fontana <cfontana@suse.de>
Fri, 6 May 2022 13:10:49 +0000 (15:10 +0200)
committerDaniel P. Berrangé <berrange@redhat.com>
Fri, 6 May 2022 14:34:30 +0000 (15:34 +0100)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Claudio Fontana <cfontana@suse.de>
src/util/iohelper.c
src/util/virfile.c
src/util/virfile.h

index ce10ccb9059ae3fb464587a4dc865b92999e9393..055540c8c48ac66da75bb5e51a44426a5a21d5d7 100644 (file)
@@ -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;
index 444a93098947aa165aabaf50e9bc79aba000c493..df16ea5d1e74df331dcef3387281b8099ee6a724 100644 (file)
@@ -4670,19 +4670,46 @@ 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;
 
-    if (fstat(fd, &sb) < 0) {
+    oflags = fcntl(disk_fd, F_GETFL);
+
+    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);
@@ -4691,23 +4718,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;
     }
@@ -4716,12 +4741,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;
@@ -4743,9 +4768,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;
@@ -4754,9 +4778,10 @@ virFileDiskCopy(const char *path, int fd, int oflags)
 #else /* WIN32 */
 
 off_t
-virFileDiskCopy(const char *path G_GNUC_UNUSED,
-                int fd G_GNUC_UNUSED,
-                int oflags G_GNUC_UNUSED)
+virFileDiskCopy(int disk_fd G_GNUC_UNUSED,
+                const char *disk_path G_GNUC_UNUSED,
+                int remote_fd G_GNUC_UNUSED,
+                const char *remote_path G_GNUC_UNUSED)
 {
     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("virFileDiskCopy unsupported on this platform"));
index 59efb760f326496824622fc91b6a0252274bd525..8e378efe3053c732620a93124c3f437d1b05c9f5 100644 (file)
@@ -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);