diff options
| author | Andrea Corallo | 2019-12-20 21:04:59 +0100 |
|---|---|---|
| committer | Andrea Corallo | 2020-01-01 11:38:14 +0100 |
| commit | 54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79 (patch) | |
| tree | 2d111c3e071039ef5c5a0e952333a110ae9112cb /src | |
| parent | 9a8f33f285295daff8ed02d35ece5e8fe11ac887 (diff) | |
| download | emacs-54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79.tar.gz emacs-54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79.zip | |
split out copy_file_fd
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 89 | ||||
| -rw-r--r-- | src/lisp.h | 3 |
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. */ | ||
| 1993 | off_t | ||
| 1994 | copy_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 | |||
| 1992 | DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6, | 2041 | DEFUN ("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 | |||
| 37 | INLINE_HEADER_BEGIN | 39 | INLINE_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 *); | |||
| 4325 | extern bool file_name_absolute_p (const char *); | 4327 | extern bool file_name_absolute_p (const char *); |
| 4326 | extern char const *get_homedir (void); | 4328 | extern char const *get_homedir (void); |
| 4327 | extern Lisp_Object expand_and_dir_to_file (Lisp_Object); | 4329 | extern Lisp_Object expand_and_dir_to_file (Lisp_Object); |
| 4330 | extern off_t copy_file_fd (int, int, struct stat *, Lisp_Object, Lisp_Object); | ||
| 4328 | extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, | 4331 | extern 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); |