1 /* Copying of files.
2 Copyright (C) 2001-2003, 2006-2007, 2009-2023 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4
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.
9
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.
14
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/>. */
17
18
19 #include <config.h>
20
21 /* Specification. */
22 #include "copy-file.h"
23
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>
30
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"
41
42 #define _(str) gettext (str)
43
44 enum { IO_SIZE = 32 * 1024 };
45
46 int
47 qcopy_file_preserving (const char *src_filename, const char *dest_filename)
48 {
49 int err = 0;
50 int src_fd;
51 struct stat statbuf;
52 int mode;
53 int dest_fd;
54
55 src_fd = open (src_filename, O_RDONLY | O_BINARY | O_CLOEXEC);
56 if (src_fd < 0)
57 return GL_COPY_ERR_OPEN_READ;
58 if (fstat (src_fd, &statbuf) < 0)
59 {
60 err = GL_COPY_ERR_OPEN_READ;
61 goto error_src;
62 }
63
64 mode = statbuf.st_mode & 07777;
65 off_t inbytes = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
66 bool empty_regular_file = inbytes == 0;
67
68 dest_fd = open (dest_filename,
69 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC,
70 0600);
71 if (dest_fd < 0)
72 {
73 err = GL_COPY_ERR_OPEN_BACKUP_WRITE;
74 goto error_src;
75 }
76
77 /* Copy the file contents. FIXME: Do not copy holes. */
78 while (0 < inbytes)
79 {
80 size_t copy_max = -1;
81 copy_max -= copy_max % IO_SIZE;
82 size_t len = inbytes < copy_max ? inbytes : copy_max;
83 ssize_t copied = copy_file_range (src_fd, NULL, dest_fd, NULL, len, 0);
84 if (copied <= 0)
85 break;
86 inbytes -= copied;
87 }
88
89 /* Finish up with read/write, in case the file was not a regular
90 file, or the file shrank or had I/O errors (in which case find
91 whether it was a read or write error). Read empty regular files
92 since they might be in /proc with their true sizes unknown until
93 they are read. */
94 if (inbytes != 0 || empty_regular_file)
95 {
96 char smallbuf[1024];
97 int bufsize = IO_SIZE;
98 char *buf = malloc (bufsize);
99 if (!buf)
100 buf = smallbuf, bufsize = sizeof smallbuf;
101
102 while (true)
103 {
104 size_t n_read = safe_read (src_fd, buf, bufsize);
105 if (n_read == 0)
106 break;
107 if (n_read == SAFE_READ_ERROR)
108 {
109 err = GL_COPY_ERR_READ;
110 break;
111 }
112 if (full_write (dest_fd, buf, n_read) < n_read)
113 {
114 err = GL_COPY_ERR_WRITE;
115 break;
116 }
117 }
118
119 if (buf != smallbuf)
120 free (buf);
121 if (err)
122 goto error_src_dest;
123 }
124
125 #if !USE_ACL
126 if (close (dest_fd) < 0)
127 {
128 err = GL_COPY_ERR_WRITE;
129 goto error_src;
130 }
131 if (close (src_fd) < 0)
132 return GL_COPY_ERR_AFTER_READ;
133 #endif
134
135 /* Preserve the access and modification times. */
136 {
137 struct timespec ts[2];
138
139 ts[0] = get_stat_atime (&statbuf);
140 ts[1] = get_stat_mtime (&statbuf);
141 utimens (dest_filename, ts);
142 }
143
144 #if HAVE_CHOWN
145 /* Preserve the owner and group. */
146 ignore_value (chown (dest_filename, statbuf.st_uid, statbuf.st_gid));
147 #endif
148
149 /* Preserve the access permissions. */
150 #if USE_ACL
151 switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode))
152 {
153 case -2:
154 err = GL_COPY_ERR_GET_ACL;
155 goto error_src_dest;
156 case -1:
157 err = GL_COPY_ERR_SET_ACL;
158 goto error_src_dest;
159 }
160 #else
161 chmod (dest_filename, mode);
162 #endif
163
164 #if USE_ACL
165 if (close (dest_fd) < 0)
166 {
167 err = GL_COPY_ERR_WRITE;
168 goto error_src;
169 }
170 if (close (src_fd) < 0)
171 return GL_COPY_ERR_AFTER_READ;
172 #endif
173
174 return 0;
175
176 error_src_dest:
177 close (dest_fd);
178 error_src:
179 close (src_fd);
180 return err;
181 }
182
183 void
184 copy_file_preserving (const char *src_filename, const char *dest_filename)
185 {
186 switch (qcopy_file_preserving (src_filename, dest_filename))
187 {
188 case 0:
189 return;
190
191 case GL_COPY_ERR_OPEN_READ:
192 error (EXIT_FAILURE, errno, _("error while opening %s for reading"),
193 quote (src_filename));
194
195 case GL_COPY_ERR_OPEN_BACKUP_WRITE:
196 error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"),
197 quote (dest_filename));
198
199 case GL_COPY_ERR_READ:
200 error (EXIT_FAILURE, errno, _("error reading %s"),
201 quote (src_filename));
202
203 case GL_COPY_ERR_WRITE:
204 error (EXIT_FAILURE, errno, _("error writing %s"),
205 quote (dest_filename));
206
207 case GL_COPY_ERR_AFTER_READ:
208 error (EXIT_FAILURE, errno, _("error after reading %s"),
209 quote (src_filename));
210
211 case GL_COPY_ERR_GET_ACL:
212 error (EXIT_FAILURE, errno, "%s", quote (src_filename));
213
214 case GL_COPY_ERR_SET_ACL:
215 error (EXIT_FAILURE, errno, _("preserving permissions for %s"),
216 quote (dest_filename));
217
218 default:
219 abort ();
220 }
221 }