This source file includes following definitions.
- create_temp_file
- open_supersede
- after_close_actions
- close_supersede
- fopen_supersede
- fclose_supersede
- fwriteerror_supersede
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22
23 #include "supersede.h"
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30
31 #if defined _WIN32 && !defined __CYGWIN__
32
33 # define WIN32_LEAN_AND_MEAN
34 # include <windows.h>
35 # include <io.h>
36 #else
37 # include <unistd.h>
38 #endif
39
40 #include "canonicalize.h"
41 #include "clean-temp.h"
42 #include "ignore-value.h"
43 #include "stat-time.h"
44 #include "utimens.h"
45 #include "acl.h"
46
47 #if defined _WIN32 && !defined __CYGWIN__
48
49 # undef MoveFileEx
50 # define MoveFileEx MoveFileExA
51 #endif
52
53 static int
54 create_temp_file (char *canon_filename, int flags, mode_t mode,
55 struct supersede_final_action *action)
56 {
57
58 size_t canon_filename_length = strlen (canon_filename);
59
60
61
62 char *temp_filename = (char *) malloc (canon_filename_length + 7 + 1);
63 if (temp_filename == NULL)
64 return -1;
65 memcpy (temp_filename, canon_filename, canon_filename_length);
66 memcpy (temp_filename + canon_filename_length, ".XXXXXX", 7 + 1);
67
68 int fd = gen_register_open_temp (temp_filename, 0, flags, mode);
69 if (fd < 0)
70 return -1;
71
72 action->final_rename_temp = temp_filename;
73 action->final_rename_dest = canon_filename;
74 return fd;
75 }
76
77 int
78 open_supersede (const char *filename, int flags, mode_t mode,
79 bool supersede_if_exists, bool supersede_if_does_not_exist,
80 struct supersede_final_action *action)
81 {
82 int fd;
83
84 int extra_flags =
85 #if defined __sun || (defined _WIN32 && !defined __CYGWIN__)
86
87
88
89
90
91 O_CREAT;
92 #else
93 0;
94 #endif
95
96 if (supersede_if_exists)
97 {
98 if (supersede_if_does_not_exist)
99 {
100 struct stat statbuf;
101
102 if (stat (filename, &statbuf) >= 0
103 && ! S_ISREG (statbuf.st_mode)
104
105
106 && ((fd = open (filename, flags | extra_flags, mode)) >= 0
107 || errno != ENOENT))
108 {
109 if (fd >= 0)
110 {
111 action->final_rename_temp = NULL;
112 action->final_rename_dest = NULL;
113 }
114 }
115 else
116 {
117
118
119 char *canon_filename =
120 canonicalize_filename_mode (filename, CAN_ALL_BUT_LAST);
121 if (canon_filename == NULL)
122 fd = -1;
123 else
124 {
125 fd = create_temp_file (canon_filename, flags, mode, action);
126 if (fd < 0)
127 free (canon_filename);
128 }
129 }
130 }
131 else
132 {
133 fd = open (filename, flags | O_CREAT | O_EXCL, mode);
134 if (fd >= 0)
135 {
136
137 action->final_rename_temp = NULL;
138 action->final_rename_dest = NULL;
139 }
140 else
141 {
142
143
144 char *canon_filename =
145 canonicalize_filename_mode (filename, CAN_ALL_BUT_LAST);
146 if (canon_filename == NULL)
147 fd = -1;
148 else
149 {
150 fd = open (canon_filename, flags | O_CREAT | O_EXCL, mode);
151 if (fd >= 0)
152 {
153
154 free (canon_filename);
155 action->final_rename_temp = NULL;
156 action->final_rename_dest = NULL;
157 }
158 else
159 {
160
161 struct stat statbuf;
162
163 if (stat (canon_filename, &statbuf) >= 0
164 && S_ISREG (statbuf.st_mode))
165 {
166
167 fd = create_temp_file (canon_filename, flags, mode,
168 action);
169 if (fd < 0)
170 free (canon_filename);
171 }
172 else
173 {
174
175
176 fd = open (canon_filename, flags | extra_flags, mode);
177 free (canon_filename);
178 if (fd >= 0)
179 {
180 action->final_rename_temp = NULL;
181 action->final_rename_dest = NULL;
182 }
183 }
184 }
185 }
186 }
187 }
188 }
189 else
190 {
191 if (supersede_if_does_not_exist)
192 {
193 fd = open (filename, flags, mode);
194 if (fd >= 0)
195 {
196
197 action->final_rename_temp = NULL;
198 action->final_rename_dest = NULL;
199 }
200 #if defined __sun || (defined _WIN32 && !defined __CYGWIN__)
201
202 else if (errno == EINVAL)
203 {
204 struct stat statbuf;
205
206 if (stat (filename, &statbuf) >= 0
207 && ! S_ISREG (statbuf.st_mode))
208 {
209
210
211
212 fd = open (filename, flags | extra_flags, mode);
213 if (fd >= 0)
214 {
215
216 action->final_rename_temp = NULL;
217 action->final_rename_dest = NULL;
218 }
219 }
220 }
221 #endif
222 else if (errno == ENOENT)
223 {
224
225 char *canon_filename =
226 canonicalize_filename_mode (filename, CAN_ALL_BUT_LAST);
227 if (canon_filename == NULL)
228 fd = -1;
229 else
230 {
231 fd = create_temp_file (canon_filename, flags, mode, action);
232 if (fd < 0)
233 free (canon_filename);
234 }
235 }
236 }
237 else
238 {
239
240 fd = open (filename, flags | O_CREAT, mode);
241 action->final_rename_temp = NULL;
242 action->final_rename_dest = NULL;
243 }
244 }
245 return fd;
246 }
247
248 static int
249 after_close_actions (int ret, const struct supersede_final_action *action)
250 {
251 if (ret < 0)
252 {
253
254 if (action->final_rename_temp != NULL)
255 {
256 int saved_errno = errno;
257 ignore_value (unlink (action->final_rename_temp));
258 free (action->final_rename_temp);
259 free (action->final_rename_dest);
260 errno = saved_errno;
261 }
262 return ret;
263 }
264
265 if (action->final_rename_temp != NULL)
266 {
267 struct stat temp_statbuf;
268 struct stat dest_statbuf;
269
270 if (stat (action->final_rename_temp, &temp_statbuf) < 0)
271 {
272
273
274 int saved_errno = errno;
275 ignore_value (unlink (action->final_rename_temp));
276 free (action->final_rename_temp);
277 free (action->final_rename_dest);
278 errno = saved_errno;
279 return -1;
280 }
281
282 if (stat (action->final_rename_dest, &dest_statbuf) >= 0)
283 {
284
285
286 {
287 struct timespec ts[2];
288
289 ts[0] = get_stat_atime (&dest_statbuf);
290 ts[1] = get_stat_mtime (&temp_statbuf);
291 ignore_value (utimens (action->final_rename_temp, ts));
292 }
293
294 #if HAVE_CHOWN
295
296
297 ignore_value (chown (action->final_rename_temp,
298 dest_statbuf.st_uid, dest_statbuf.st_gid));
299 #endif
300
301
302
303 #if USE_ACL
304 switch (qcopy_acl (action->final_rename_dest, -1,
305 action->final_rename_temp, -1,
306 dest_statbuf.st_mode))
307 {
308 case -2:
309
310 case -1:
311
312 ignore_value (unlink (action->final_rename_temp));
313 free (action->final_rename_temp);
314 free (action->final_rename_dest);
315 errno = EPERM;
316 return -1;
317 }
318 #else
319 chmod (action->final_rename_temp, dest_statbuf.st_mode);
320 #endif
321 }
322 else
323
324
325 ;
326
327
328 #if defined _WIN32 && !defined __CYGWIN__
329
330
331
332
333
334
335
336
337
338 if (!MoveFileEx (action->final_rename_temp, action->final_rename_dest,
339 MOVEFILE_REPLACE_EXISTING))
340 {
341 int saved_errno;
342 switch (GetLastError ())
343 {
344 case ERROR_INVALID_PARAMETER:
345 saved_errno = EINVAL; break;
346 default:
347 saved_errno = EIO; break;
348 }
349 ignore_value (unlink (action->final_rename_temp));
350 free (action->final_rename_temp);
351 free (action->final_rename_dest);
352 errno = saved_errno;
353 return -1;
354 }
355 #else
356 if (rename (action->final_rename_temp, action->final_rename_dest) < 0)
357 {
358 int saved_errno = errno;
359 ignore_value (unlink (action->final_rename_temp));
360 free (action->final_rename_temp);
361 free (action->final_rename_dest);
362 errno = saved_errno;
363 return -1;
364 }
365 #endif
366
367 unregister_temporary_file (action->final_rename_temp);
368
369 free (action->final_rename_temp);
370 free (action->final_rename_dest);
371 }
372
373 return ret;
374 }
375
376 int
377 close_supersede (int fd, const struct supersede_final_action *action)
378 {
379 if (fd < 0)
380 {
381 free (action->final_rename_temp);
382 free (action->final_rename_dest);
383 return fd;
384 }
385
386 int ret;
387 if (action->final_rename_temp != NULL)
388 ret = close_temp (fd);
389 else
390 ret = close (fd);
391 return after_close_actions (ret, action);
392 }
393
394 FILE *
395 fopen_supersede (const char *filename, const char *mode,
396 bool supersede_if_exists, bool supersede_if_does_not_exist,
397 struct supersede_final_action *action)
398 {
399
400 int open_direction = 0;
401 int open_flags = 0;
402 {
403 const char *p = mode;
404
405 for (; *p != '\0'; p++)
406 {
407 switch (*p)
408 {
409 case 'r':
410 open_direction = O_RDONLY;
411 continue;
412 case 'w':
413 open_direction = O_WRONLY;
414 open_flags |= O_TRUNC;
415 continue;
416 case 'a':
417 open_direction = O_WRONLY;
418 open_flags |= O_APPEND;
419 continue;
420 case 'b':
421
422
423 open_flags |= O_BINARY;
424 continue;
425 case '+':
426 open_direction = O_RDWR;
427 continue;
428 case 'x':
429
430 continue;
431 case 'e':
432 open_flags |= O_CLOEXEC;
433 continue;
434 default:
435 break;
436 }
437 break;
438 }
439 }
440
441 mode_t open_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
442 int fd = open_supersede (filename, open_direction | open_flags, open_mode,
443 supersede_if_exists, supersede_if_does_not_exist,
444 action);
445 if (fd < 0)
446 return NULL;
447
448 FILE *stream = fdopen (fd, mode);
449 if (stream == NULL)
450 {
451 int saved_errno = errno;
452 close (fd);
453 close_supersede (-1, action);
454 errno = saved_errno;
455 }
456 return stream;
457 }
458
459 int
460 fclose_supersede (FILE *stream, const struct supersede_final_action *action)
461 {
462 if (stream == NULL)
463 return -1;
464 int ret;
465 if (action->final_rename_temp != NULL)
466 ret = fclose_temp (stream);
467 else
468 ret = fclose (stream);
469 return after_close_actions (ret, action);
470 }
471
472 #if GNULIB_FWRITEERROR
473 int
474 fwriteerror_supersede (FILE *stream, const struct supersede_final_action *action)
475 {
476 if (stream == NULL)
477 return -1;
478 int ret;
479 if (action->final_rename_temp != NULL)
480 ret = fclose_temp (stream);
481 else
482 ret = fclose (stream);
483 return after_close_actions (ret, action);
484 }
485 #endif