2 Copyright (C) 2001-2003, 2006-2007, 2009-2018 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/>. */
22 #include "copy-file.h"
32 #include "ignore-value.h"
33 #include "safe-read.h"
34 #include "full-write.h"
35 #include "stat-time.h"
38 #include "binary-io.h"
43 #define _(str) gettext (str)
45 enum { IO_SIZE
= 32 * 1024 };
48 qcopy_file_preserving (const char *src_filename
, const char *dest_filename
)
55 char *buf
= xmalloc (IO_SIZE
);
57 src_fd
= open (src_filename
, O_RDONLY
| O_BINARY
);
60 err
= GL_COPY_ERR_OPEN_READ
;
63 if (fstat (src_fd
, &statbuf
) < 0)
65 err
= GL_COPY_ERR_OPEN_READ
;
69 mode
= statbuf
.st_mode
& 07777;
71 dest_fd
= open (dest_filename
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, 0600);
74 err
= GL_COPY_ERR_OPEN_BACKUP_WRITE
;
78 /* Copy the file contents. */
81 size_t n_read
= safe_read (src_fd
, buf
, IO_SIZE
);
82 if (n_read
== SAFE_READ_ERROR
)
84 err
= GL_COPY_ERR_READ
;
90 if (full_write (dest_fd
, buf
, n_read
) < n_read
)
92 err
= GL_COPY_ERR_WRITE
;
98 buf
= NULL
; /* To avoid double free in error case. */
101 if (close (dest_fd
) < 0)
103 err
= GL_COPY_ERR_WRITE
;
106 if (close (src_fd
) < 0)
108 err
= GL_COPY_ERR_AFTER_READ
;
113 /* Preserve the access and modification times. */
115 struct timespec ts
[2];
117 ts
[0] = get_stat_atime (&statbuf
);
118 ts
[1] = get_stat_mtime (&statbuf
);
119 utimens (dest_filename
, ts
);
123 /* Preserve the owner and group. */
124 ignore_value (chown (dest_filename
, statbuf
.st_uid
, statbuf
.st_gid
));
127 /* Preserve the access permissions. */
129 switch (qcopy_acl (src_filename
, src_fd
, dest_filename
, dest_fd
, mode
))
132 err
= GL_COPY_ERR_GET_ACL
;
135 err
= GL_COPY_ERR_SET_ACL
;
139 chmod (dest_filename
, mode
);
143 if (close (dest_fd
) < 0)
145 err
= GL_COPY_ERR_WRITE
;
148 if (close (src_fd
) < 0)
150 err
= GL_COPY_ERR_AFTER_READ
;
167 copy_file_preserving (const char *src_filename
, const char *dest_filename
)
169 switch (qcopy_file_preserving (src_filename
, dest_filename
))
174 case GL_COPY_ERR_OPEN_READ
:
175 error (EXIT_FAILURE
, errno
, _("error while opening %s for reading"),
176 quote (src_filename
));
178 case GL_COPY_ERR_OPEN_BACKUP_WRITE
:
179 error (EXIT_FAILURE
, errno
, _("cannot open backup file %s for writing"),
180 quote (dest_filename
));
182 case GL_COPY_ERR_READ
:
183 error (EXIT_FAILURE
, errno
, _("error reading %s"),
184 quote (src_filename
));
186 case GL_COPY_ERR_WRITE
:
187 error (EXIT_FAILURE
, errno
, _("error writing %s"),
188 quote (dest_filename
));
190 case GL_COPY_ERR_AFTER_READ
:
191 error (EXIT_FAILURE
, errno
, _("error after reading %s"),
192 quote (src_filename
));
194 case GL_COPY_ERR_GET_ACL
:
195 error (EXIT_FAILURE
, errno
, "%s", quote (src_filename
));
197 case GL_COPY_ERR_SET_ACL
:
198 error (EXIT_FAILURE
, errno
, _("preserving permissions for %s"),
199 quote (dest_filename
));