[libvirt RFCv6 05/27] virfile: change virFileDiskCopy arguments to extend beyond stdin, stdout

Claudio Fontana posted 27 patches 3 years, 9 months ago
There is a newer version of this series
[libvirt RFCv6 05/27] virfile: change virFileDiskCopy arguments to extend beyond stdin, stdout
Posted by Claudio Fontana 3 years, 9 months ago
Signed-off-by: Claudio Fontana <cfontana@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.35.3
Re: [libvirt RFCv6 05/27] virfile: change virFileDiskCopy arguments to extend beyond stdin, stdout
Posted by Daniel P. Berrangé 3 years, 9 months ago
On Thu, May 05, 2022 at 02:52:19PM +0200, Claudio Fontana wrote:
> Signed-off-by: Claudio Fontana <cfontana@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 */

With this issue, and the posix_memalign issue, I'm inclined to say we
should just take the easy way out and hide virFileDiskCopy behind
#ifndef WIN32, since we don't even need it on WIN32.


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [libvirt RFCv6 05/27] virfile: change virFileDiskCopy arguments to extend beyond stdin, stdout
Posted by Claudio Fontana 3 years, 9 months ago
On 5/6/22 1:03 PM, Daniel P. Berrangé wrote:
> On Thu, May 05, 2022 at 02:52:19PM +0200, Claudio Fontana wrote:
>> Signed-off-by: Claudio Fontana <cfontana@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 */
> 
> With this issue, and the posix_memalign issue, I'm inclined to say we
> should just take the easy way out and hide virFileDiskCopy behind
> #ifndef WIN32, since we don't even need it on WIN32.
> 

Ah ok this works too. Thanks!

Claudio