Fix last ChangeLog entry.
[gnulib.git] / lib / copy-file.c
blobddcee13f34de52986de544bbcdcded35ed8beb51
1 /* Copying of files.
2 Copyright (C) 2001-2003, 2006-2007, 2009-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
19 #include <config.h>
21 /* Specification. */
22 #include "copy-file.h"
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
31 #include <error.h>
32 #include "ignore-value.h"
33 #include "safe-read.h"
34 #include "full-write.h"
35 #include "stat-time.h"
36 #include "utimens.h"
37 #include "acl.h"
38 #include "binary-io.h"
39 #include "quote.h"
40 #include "gettext.h"
42 #define _(msgid) dgettext ("gnulib", msgid)
44 enum { IO_SIZE = 32 * 1024 };
46 static int
47 copy_file_internal (const char *src_filename, const char *dest_filename,
48 bool preserve)
50 int err = 0;
51 int src_fd;
52 struct stat statbuf;
53 int mode;
54 int dest_fd;
56 src_fd = open (src_filename, O_RDONLY | O_BINARY | O_CLOEXEC);
57 if (src_fd < 0)
58 return GL_COPY_ERR_OPEN_READ;
59 if (fstat (src_fd, &statbuf) < 0)
61 err = GL_COPY_ERR_OPEN_READ;
62 goto error_src;
65 mode = statbuf.st_mode & 07777;
66 off_t inbytes = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
67 bool empty_regular_file = inbytes == 0;
69 dest_fd = open (dest_filename,
70 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC,
71 /* If preserve is true, we must assume that the file may
72 have confidential contents. Therefore open it with mode
73 0600 and assign the permissions at the end.
74 If preserve is false, open it with mode 0666 & ~umask. */
75 preserve ? 0600 : 0666);
76 if (dest_fd < 0)
78 err = GL_COPY_ERR_OPEN_BACKUP_WRITE;
79 goto error_src;
82 /* Copy the file contents. FIXME: Do not copy holes. */
83 while (0 < inbytes)
85 size_t copy_max = -1;
86 copy_max -= copy_max % IO_SIZE;
87 size_t len = inbytes < copy_max ? inbytes : copy_max;
88 ssize_t copied = copy_file_range (src_fd, NULL, dest_fd, NULL, len, 0);
89 if (copied <= 0)
90 break;
91 inbytes -= copied;
94 /* Finish up with read/write, in case the file was not a regular
95 file, or the file shrank or had I/O errors (in which case find
96 whether it was a read or write error). Read empty regular files
97 since they might be in /proc with their true sizes unknown until
98 they are read. */
99 if (inbytes != 0 || empty_regular_file)
101 char smallbuf[1024];
102 int bufsize = IO_SIZE;
103 char *buf = malloc (bufsize);
104 if (!buf)
105 buf = smallbuf, bufsize = sizeof smallbuf;
107 while (true)
109 size_t n_read = safe_read (src_fd, buf, bufsize);
110 if (n_read == 0)
111 break;
112 if (n_read == SAFE_READ_ERROR)
114 err = GL_COPY_ERR_READ;
115 break;
117 if (full_write (dest_fd, buf, n_read) < n_read)
119 err = GL_COPY_ERR_WRITE;
120 break;
124 if (buf != smallbuf)
125 free (buf);
126 if (err)
127 goto error_src_dest;
130 #if !USE_ACL
131 if (close (dest_fd) < 0)
133 err = GL_COPY_ERR_WRITE;
134 goto error_src;
136 if (close (src_fd) < 0)
137 return GL_COPY_ERR_AFTER_READ;
138 #endif
140 if (preserve)
142 /* Preserve the access and modification times. */
144 struct timespec ts[2];
146 ts[0] = get_stat_atime (&statbuf);
147 ts[1] = get_stat_mtime (&statbuf);
148 utimens (dest_filename, ts);
151 #if HAVE_CHOWN
152 /* Preserve the owner and group. */
153 ignore_value (chown (dest_filename, statbuf.st_uid, statbuf.st_gid));
154 #endif
156 /* Preserve the access permissions. */
157 #if USE_ACL
158 switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode))
160 case -2:
161 err = GL_COPY_ERR_GET_ACL;
162 goto error_src_dest;
163 case -1:
164 err = GL_COPY_ERR_SET_ACL;
165 goto error_src_dest;
167 #else
168 chmod (dest_filename, mode);
169 #endif
172 #if USE_ACL
173 if (close (dest_fd) < 0)
175 err = GL_COPY_ERR_WRITE;
176 goto error_src;
178 if (close (src_fd) < 0)
179 return GL_COPY_ERR_AFTER_READ;
180 #endif
182 return 0;
184 error_src_dest:
185 close (dest_fd);
186 error_src:
187 close (src_fd);
188 return err;
192 qcopy_file_preserving (const char *src_filename, const char *dest_filename)
194 return copy_file_internal (src_filename, dest_filename, true);
198 copy_file_to (const char *src_filename, const char *dest_filename)
200 return copy_file_internal (src_filename, dest_filename, false);
203 static void
204 handle_error_code (int err, const char *src_filename, const char *dest_filename)
206 switch (err)
208 case 0:
209 return;
211 case GL_COPY_ERR_OPEN_READ:
212 error (EXIT_FAILURE, errno, _("error while opening %s for reading"),
213 quote (src_filename));
215 case GL_COPY_ERR_OPEN_BACKUP_WRITE:
216 error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"),
217 quote (dest_filename));
219 case GL_COPY_ERR_READ:
220 error (EXIT_FAILURE, errno, _("error reading %s"),
221 quote (src_filename));
223 case GL_COPY_ERR_WRITE:
224 error (EXIT_FAILURE, errno, _("error writing %s"),
225 quote (dest_filename));
227 case GL_COPY_ERR_AFTER_READ:
228 error (EXIT_FAILURE, errno, _("error after reading %s"),
229 quote (src_filename));
231 case GL_COPY_ERR_GET_ACL:
232 error (EXIT_FAILURE, errno, "%s", quote (src_filename));
234 case GL_COPY_ERR_SET_ACL:
235 error (EXIT_FAILURE, errno, _("preserving permissions for %s"),
236 quote (dest_filename));
238 default:
239 abort ();
243 void
244 xcopy_file_preserving (const char *src_filename, const char *dest_filename)
246 int err = qcopy_file_preserving (src_filename, dest_filename);
247 handle_error_code (err, src_filename, dest_filename);
250 void
251 copy_file_preserving (const char *src_filename, const char *dest_filename)
253 xcopy_file_preserving (src_filename, dest_filename);
256 void
257 xcopy_file_to (const char *src_filename, const char *dest_filename)
259 int err = copy_file_to (src_filename, dest_filename);
260 handle_error_code (err, src_filename, dest_filename);