comparison lib/copy-file.c @ 16273:d50152d6b5d2

copy-file: add error-code-returning variant. * lib/copy-file.h (GL_COPY_ERR_*): New enumeration items. (qcopy_file_preserving): New declaration. * lib/copy-file.c (qcopy_file_preserving): Renamed from copy_file_preserving. Change return type to 'int'. Don't emit an error message here. (copy_file_preserving): New function. * tests/test-copy-file.c: Include <stdlib.h>. (main): Test qcopy_file_preserving if the environment variable NO_STDERR_OUTPUT is set. * tests/test-copy-file-1.sh: Invoke test-copy-file.sh a second time, with NO_STDERR_OUTPUT * tests/test-copy-file-2.sh: Likewise.
author Reuben Thomas <rrt@sc3d.org>
date Thu, 12 Jan 2012 03:04:49 +0100
parents 8e1f4b31c39f
children e542fd46ad6f
comparison
equal deleted inserted replaced
16272:8e1f4b31c39f 16273:d50152d6b5d2
52 #undef open 52 #undef open
53 #undef close 53 #undef close
54 54
55 enum { IO_SIZE = 32 * 1024 }; 55 enum { IO_SIZE = 32 * 1024 };
56 56
57 void 57 int
58 copy_file_preserving (const char *src_filename, const char *dest_filename) 58 qcopy_file_preserving (const char *src_filename, const char *dest_filename)
59 { 59 {
60 int err = 0;
60 int src_fd; 61 int src_fd;
61 struct stat statbuf; 62 struct stat statbuf;
62 int mode; 63 int mode;
63 int dest_fd; 64 int dest_fd;
64 char *buf = xmalloc (IO_SIZE); 65 char *buf = xmalloc (IO_SIZE);
65 66
66 src_fd = open (src_filename, O_RDONLY | O_BINARY); 67 src_fd = open (src_filename, O_RDONLY | O_BINARY);
67 if (src_fd < 0 || fstat (src_fd, &statbuf) < 0) 68 if (src_fd < 0)
68 error (EXIT_FAILURE, errno, _("error while opening %s for reading"), 69 {
69 quote (src_filename)); 70 err = GL_COPY_ERR_OPEN_READ;
71 goto error;
72 }
73 if (fstat (src_fd, &statbuf) < 0)
74 {
75 err = GL_COPY_ERR_OPEN_READ;
76 goto error_src;
77 }
70 78
71 mode = statbuf.st_mode & 07777; 79 mode = statbuf.st_mode & 07777;
72 80
73 dest_fd = open (dest_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600); 81 dest_fd = open (dest_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
74 if (dest_fd < 0) 82 if (dest_fd < 0)
75 error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"), 83 {
76 quote (dest_filename)); 84 err = GL_COPY_ERR_OPEN_BACKUP_WRITE;
85 goto error_src;
86 }
77 87
78 /* Copy the file contents. */ 88 /* Copy the file contents. */
79 for (;;) 89 for (;;)
80 { 90 {
81 size_t n_read = safe_read (src_fd, buf, IO_SIZE); 91 size_t n_read = safe_read (src_fd, buf, IO_SIZE);
82 if (n_read == SAFE_READ_ERROR) 92 if (n_read == SAFE_READ_ERROR)
83 error (EXIT_FAILURE, errno, _("error reading %s"), 93 {
84 quote (src_filename)); 94 err = GL_COPY_ERR_READ;
95 goto error_src_dest;
96 }
85 if (n_read == 0) 97 if (n_read == 0)
86 break; 98 break;
87 99
88 if (full_write (dest_fd, buf, n_read) < n_read) 100 if (full_write (dest_fd, buf, n_read) < n_read)
89 error (EXIT_FAILURE, errno, _("error writing %s"), 101 {
90 quote (est_filename)); 102 err = GL_COPY_ERR_WRITE;
103 goto error_src_dest;
104 }
91 } 105 }
92 106
93 free (buf); 107 free (buf);
94 108
95 #if !USE_ACL 109 #if !USE_ACL
96 if (close (dest_fd) < 0) 110 if (close (dest_fd) < 0)
97 error (EXIT_FAILURE, errno, _("error writing %s"), quote (dest_filename)); 111 {
112 err = GL_COPY_ERR_WRITE;
113 goto error_src;
114 }
98 if (close (src_fd) < 0) 115 if (close (src_fd) < 0)
99 error (EXIT_FAILURE, errno, _("error after reading %s"), 116 {
100 quote (src_filename)); 117 err = GL_COPY_ERR_AFTER_READ;
118 goto error;
119 }
101 #endif 120 #endif
102 121
103 /* Preserve the access and modification times. */ 122 /* Preserve the access and modification times. */
104 #if HAVE_UTIME 123 #if HAVE_UTIME
105 { 124 {
127 /* Preserve the access permissions. */ 146 /* Preserve the access permissions. */
128 #if USE_ACL 147 #if USE_ACL
129 switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode)) 148 switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode))
130 { 149 {
131 case -2: 150 case -2:
151 err = GL_COPY_ERR_GET_ACL;
152 goto error_src_dest;
153 case -1:
154 err = GL_COPY_ERR_SET_ACL;
155 goto error_src_dest;
156 }
157 #else
158 chmod (dest_filename, mode);
159 #endif
160
161 #if USE_ACL
162 if (close (dest_fd) < 0)
163 {
164 err = GL_COPY_ERR_WRITE;
165 goto error_src;
166 }
167 if (close (src_fd) < 0)
168 {
169 err = GL_COPY_ERR_AFTER_READ;
170 goto error;
171 }
172 #endif
173
174 return 0;
175
176 error_src_dest:
177 close (dest_fd);
178 error_src:
179 close (src_fd);
180 error:
181 return err;
182 }
183
184 void
185 copy_file_preserving (const char *src_filename, const char *dest_filename)
186 {
187 switch (qcopy_file_preserving (src_filename, dest_filename))
188 {
189 case 0:
190 return;
191
192 case GL_COPY_ERR_OPEN_READ:
193 error (EXIT_FAILURE, errno, _("error while opening %s for reading"),
194 quote (src_filename));
195
196 case GL_COPY_ERR_OPEN_BACKUP_WRITE:
197 error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"),
198 quote (dest_filename));
199
200 case GL_COPY_ERR_READ:
201 error (EXIT_FAILURE, errno, _("error reading %s"),
202 quote (src_filename));
203
204 case GL_COPY_ERR_WRITE:
205 error (EXIT_FAILURE, errno, _("error writing %s"),
206 quote (dest_filename));
207
208 case GL_COPY_ERR_AFTER_READ:
209 error (EXIT_FAILURE, errno, _("error after reading %s"),
210 quote (src_filename));
211
212 case GL_COPY_ERR_GET_ACL:
132 error (EXIT_FAILURE, errno, "%s", quote (src_filename)); 213 error (EXIT_FAILURE, errno, "%s", quote (src_filename));
133 case -1: 214
215 case GL_COPY_ERR_SET_ACL:
134 error (EXIT_FAILURE, errno, _("preserving permissions for %s"), 216 error (EXIT_FAILURE, errno, _("preserving permissions for %s"),
135 quote (dest_filename)); 217 quote (dest_filename));
136 } 218
137 #else 219 default:
138 chmod (dest_filename, mode); 220 abort ();
139 #endif 221 }
140
141 #if USE_ACL
142 if (close (dest_fd) < 0)
143 error (EXIT_FAILURE, errno, _("error writing %s"), quote (dest_filename));
144 if (close (src_fd) < 0)
145 error (EXIT_FAILURE, errno, _("error after reading %s"),
146 quote (src_filename));
147 #endif
148 } 222 }