aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrea Corallo2019-12-20 21:04:59 +0100
committerAndrea Corallo2020-01-01 11:38:14 +0100
commit54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79 (patch)
tree2d111c3e071039ef5c5a0e952333a110ae9112cb /src
parent9a8f33f285295daff8ed02d35ece5e8fe11ac887 (diff)
downloademacs-54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79.tar.gz
emacs-54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79.zip
split out copy_file_fd
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c89
-rw-r--r--src/lisp.h3
2 files changed, 53 insertions, 39 deletions
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)
1989} 1989}
1990#endif 1990#endif
1991 1991
1992/* Copy data to OFD from IFD if possible. Return NEWSIZE. */
1993off_t
1994copy_file_fd (int ofd, int ifd, struct stat *st, Lisp_Object newname,
1995 Lisp_Object file)
1996{
1997 off_t newsize;
1998
1999 if (clone_file (ofd, ifd))
2000 newsize = st->st_size;
2001 else
2002 {
2003 off_t insize = st->st_size;
2004 ssize_t copied;
2005
2006 for (newsize = 0; newsize < insize; newsize += copied)
2007 {
2008 /* Copy at most COPY_MAX bytes at a time; this is min
2009 (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
2010 surely aligned well. */
2011 ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
2012 ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30;
2013 off_t intail = insize - newsize;
2014 ptrdiff_t len = min (intail, copy_max);
2015 copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0);
2016 if (copied <= 0)
2017 break;
2018 maybe_quit ();
2019 }
2020
2021 /* Fall back on read+write if copy_file_range failed, or if the
2022 input is empty and so could be a /proc file. read+write will
2023 either succeed, or report an error more precisely than
2024 copy_file_range would. */
2025 if (newsize != insize || insize == 0)
2026 {
2027 char buf[MAX_ALLOCA];
2028 for (; (copied = emacs_read_quit (ifd, buf, sizeof buf));
2029 newsize += copied)
2030 {
2031 if (copied < 0)
2032 report_file_error ("Read error", file);
2033 if (emacs_write_quit (ofd, buf, copied) != copied)
2034 report_file_error ("Write error", newname);
2035 }
2036 }
2037 }
2038 return newsize;
2039}
2040
1992DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6, 2041DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6,
1993 "fCopy file: \nGCopy %s to file: \np\nP", 2042 "fCopy file: \nGCopy %s to file: \np\nP",
1994 doc: /* Copy FILE to NEWNAME. Both args must be strings. 2043 doc: /* Copy FILE to NEWNAME. Both args must be strings.
@@ -2143,45 +2192,7 @@ permissions. */)
2143 2192
2144 maybe_quit (); 2193 maybe_quit ();
2145 2194
2146 if (clone_file (ofd, ifd)) 2195 newsize = copy_file_fd (ofd, ifd, &st, newname, file);
2147 newsize = st.st_size;
2148 else
2149 {
2150 off_t insize = st.st_size;
2151 ssize_t copied;
2152
2153 for (newsize = 0; newsize < insize; newsize += copied)
2154 {
2155 /* Copy at most COPY_MAX bytes at a time; this is min
2156 (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is
2157 surely aligned well. */
2158 ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
2159 ptrdiff_t copy_max = min (ssize_max, SIZE_MAX) >> 30 << 30;
2160 off_t intail = insize - newsize;
2161 ptrdiff_t len = min (intail, copy_max);
2162 copied = copy_file_range (ifd, NULL, ofd, NULL, len, 0);
2163 if (copied <= 0)
2164 break;
2165 maybe_quit ();
2166 }
2167
2168 /* Fall back on read+write if copy_file_range failed, or if the
2169 input is empty and so could be a /proc file. read+write will
2170 either succeed, or report an error more precisely than
2171 copy_file_range would. */
2172 if (newsize != insize || insize == 0)
2173 {
2174 char buf[MAX_ALLOCA];
2175 for (; (copied = emacs_read_quit (ifd, buf, sizeof buf));
2176 newsize += copied)
2177 {
2178 if (copied < 0)
2179 report_file_error ("Read error", file);
2180 if (emacs_write_quit (ofd, buf, copied) != copied)
2181 report_file_error ("Write error", newname);
2182 }
2183 }
2184 }
2185 2196
2186 /* Truncate any existing output file after writing the data. This 2197 /* Truncate any existing output file after writing the data. This
2187 is more likely to work than truncation before writing, if the 2198 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 <https://www.gnu.org/licenses/>. */
34#include <intprops.h> 34#include <intprops.h>
35#include <verify.h> 35#include <verify.h>
36 36
37#include <sys/stat.h>
38
37INLINE_HEADER_BEGIN 39INLINE_HEADER_BEGIN
38 40
39/* Define a TYPE constant ID as an externally visible name. Use like this: 41/* 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 *);
4325extern bool file_name_absolute_p (const char *); 4327extern bool file_name_absolute_p (const char *);
4326extern char const *get_homedir (void); 4328extern char const *get_homedir (void);
4327extern Lisp_Object expand_and_dir_to_file (Lisp_Object); 4329extern Lisp_Object expand_and_dir_to_file (Lisp_Object);
4330extern off_t copy_file_fd (int, int, struct stat *, Lisp_Object, Lisp_Object);
4328extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, 4331extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object,
4329 Lisp_Object, Lisp_Object, Lisp_Object, 4332 Lisp_Object, Lisp_Object, Lisp_Object,
4330 Lisp_Object, int); 4333 Lisp_Object, int);