From: Andrea Corallo Date: Fri, 20 Dec 2019 20:04:59 +0000 (+0100) Subject: split out copy_file_fd X-Git-Tag: emacs-28.0.90~2727^2~905 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79;p=emacs.git split out copy_file_fd --- diff --git a/src/fileio.c b/src/fileio.c index 6e2fe2f0b82..91e0efc0a83 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -1989,6 +1989,55 @@ clone_file (int dest, int source) } #endif +/* Copy data to OFD from IFD if possible. Return NEWSIZE. */ +off_t +copy_file_fd (int ofd, int ifd, struct stat *st, Lisp_Object newname, + Lisp_Object file) +{ + off_t newsize; + + if (clone_file (ofd, ifd)) + newsize = st->st_size; + else + { + off_t insize = st->st_size; + ssize_t copied; + + for (newsize = 0; newsize < insize; newsize += copied) + { + /* Copy at most COPY_MAX bytes at a time; this is min + (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is + surely aligned well. */ + ssize_t ssize_max = TYPE_MAXIMUM (ssize_t); + ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30; + off_t intail = insize - newsize; + ptrdiff_t len = min (intail, copy_max); + copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0); + if (copied <= 0) + break; + maybe_quit (); + } + + /* Fall back on read+write if copy_file_range failed, or if the + input is empty and so could be a /proc file. read+write will + either succeed, or report an error more precisely than + copy_file_range would. */ + if (newsize != insize || insize == 0) + { + char buf[MAX_ALLOCA]; + for (; (copied = emacs_read_quit (ifd, buf, sizeof buf)); + newsize += copied) + { + if (copied < 0) + report_file_error ("Read error", file); + if (emacs_write_quit (ofd, buf, copied) != copied) + report_file_error ("Write error", newname); + } + } + } + return newsize; +} + DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6, "fCopy file: \nGCopy %s to file: \np\nP", doc: /* Copy FILE to NEWNAME. Both args must be strings. @@ -2143,45 +2192,7 @@ permissions. */) maybe_quit (); - if (clone_file (ofd, ifd)) - newsize = st.st_size; - else - { - off_t insize = st.st_size; - ssize_t copied; - - for (newsize = 0; newsize < insize; newsize += copied) - { - /* Copy at most COPY_MAX bytes at a time; this is min - (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is - surely aligned well. */ - ssize_t ssize_max = TYPE_MAXIMUM (ssize_t); - ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30; - off_t intail = insize - newsize; - ptrdiff_t len = min (intail, copy_max); - copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0); - if (copied <= 0) - break; - maybe_quit (); - } - - /* Fall back on read+write if copy_file_range failed, or if the - input is empty and so could be a /proc file. read+write will - either succeed, or report an error more precisely than - copy_file_range would. */ - if (newsize != insize || insize == 0) - { - char buf[MAX_ALLOCA]; - for (; (copied = emacs_read_quit (ifd, buf, sizeof buf)); - newsize += copied) - { - if (copied < 0) - report_file_error ("Read error", file); - if (emacs_write_quit (ofd, buf, copied) != copied) - report_file_error ("Write error", newname); - } - } - } + newsize = copy_file_fd (ofd, ifd, &st, newname, file); /* Truncate any existing output file after writing the data. This is more likely to work than truncation before writing, if the diff --git a/src/lisp.h b/src/lisp.h index 05d6ef0d22a..7a4b3517574 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -34,6 +34,8 @@ along with GNU Emacs. If not, see . */ #include #include +#include + INLINE_HEADER_BEGIN /* Define a TYPE constant ID as an externally visible name. Use like this: @@ -4325,6 +4327,7 @@ extern char *splice_dir_file (char *, char const *, char const *); extern bool file_name_absolute_p (const char *); extern char const *get_homedir (void); extern Lisp_Object expand_and_dir_to_file (Lisp_Object); +extern off_t copy_file_fd (int, int, struct stat *, Lisp_Object, Lisp_Object); extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, int);