Mercurial > dovecot > core-2.2
annotate src/lib/file-copy.c @ 22664:fea53c2725c0
director: Fix director_max_parallel_moves/kicks type
Should be uint, not time.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Thu, 09 Nov 2017 12:24:16 +0200 |
parents | 2e2563132d5f |
children | cb108f786fb4 |
rev | line source |
---|---|
21390
2e2563132d5f
Updated copyright notices to include the year 2017.
Stephan Bosch <stephan.bosch@dovecot.fi>
parents:
19552
diff
changeset
|
1 /* Copyright (c) 2006-2017 Dovecot authors, see the included COPYING file */ |
4406 | 2 |
3 #include "lib.h" | |
4 #include "istream.h" | |
5 #include "ostream.h" | |
6 #include "file-copy.h" | |
7 | |
8 #include <stdio.h> | |
9 #include <unistd.h> | |
10 #include <fcntl.h> | |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
11 #include <sys/stat.h> |
4406 | 12 |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
13 static int file_copy_to_tmp(const char *srcpath, const char *tmppath, |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
14 bool try_hardlink) |
4406 | 15 { |
16 struct istream *input; | |
17 struct ostream *output; | |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
18 struct stat st; |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
19 mode_t old_umask; |
4406 | 20 int fd_in, fd_out; |
21 off_t ret; | |
22 | |
23 if (try_hardlink) { | |
24 /* see if hardlinking works */ | |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
25 if (link(srcpath, tmppath) == 0) |
4406 | 26 return 1; |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
27 if (errno == EEXIST) { |
19136
fefaa6d09a81
Replaced unlink() calls with i_unlink*() wherever possible.
Timo Sirainen <tss@iki.fi>
parents:
18137
diff
changeset
|
28 if (i_unlink_if_exists(tmppath) < 0) |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
29 return -1; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
30 if (link(srcpath, tmppath) == 0) |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
31 return 1; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
32 } |
4406 | 33 if (errno == ENOENT) |
34 return 0; | |
35 if (!ECANTLINK(errno)) { | |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
36 i_error("link(%s, %s) failed: %m", srcpath, tmppath); |
4406 | 37 return -1; |
38 } | |
39 | |
40 /* fallback to manual copying */ | |
41 } | |
42 | |
43 fd_in = open(srcpath, O_RDONLY); | |
44 if (fd_in == -1) { | |
45 if (errno == ENOENT) | |
46 return 0; | |
47 i_error("open(%s) failed: %m", srcpath); | |
48 return -1; | |
49 } | |
50 | |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
51 if (fstat(fd_in, &st) < 0) { |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
52 i_error("fstat(%s) failed: %m", srcpath); |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
53 i_close_fd(&fd_in); |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
54 return -1; |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
55 } |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
56 |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
57 old_umask = umask(0); |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
58 fd_out = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode); |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
59 umask(old_umask); |
4406 | 60 if (fd_out == -1) { |
61 i_error("open(%s, O_CREAT) failed: %m", tmppath); | |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
62 i_close_fd(&fd_in); |
4406 | 63 return -1; |
64 } | |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
65 |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
66 /* try to change the group, don't really care if it fails */ |
6653
947a8a032371
Log an error if fchown() fails, but not because of EPERM.
Timo Sirainen <tss@iki.fi>
parents:
6429
diff
changeset
|
67 if (fchown(fd_out, (uid_t)-1, st.st_gid) < 0 && errno != EPERM) |
947a8a032371
Log an error if fchown() fails, but not because of EPERM.
Timo Sirainen <tss@iki.fi>
parents:
6429
diff
changeset
|
68 i_error("fchown(%s) failed: %m", tmppath); |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
69 |
13885
59f5238c6e61
istream: Don't treat max_block_size=0 as unlimited.
Timo Sirainen <tss@iki.fi>
parents:
12782
diff
changeset
|
70 input = i_stream_create_fd(fd_in, IO_BLOCK_SIZE, FALSE); |
6161
c62f7ee79446
Split o_stream_create_file() to _create_fd() and _create_fd_file().
Timo Sirainen <tss@iki.fi>
parents:
6142
diff
changeset
|
71 output = o_stream_create_fd_file(fd_out, 0, FALSE); |
4406 | 72 |
73 while ((ret = o_stream_send_istream(output, input)) > 0) ; | |
74 | |
6670
03af6da2ace1
If o_stream_send_istream() fails, log an error.
Timo Sirainen <tss@iki.fi>
parents:
6653
diff
changeset
|
75 if (ret < 0) |
03af6da2ace1
If o_stream_send_istream() fails, log an error.
Timo Sirainen <tss@iki.fi>
parents:
6653
diff
changeset
|
76 i_error("write(%s) failed: %m", tmppath); |
03af6da2ace1
If o_stream_send_istream() fails, log an error.
Timo Sirainen <tss@iki.fi>
parents:
6653
diff
changeset
|
77 |
4406 | 78 i_stream_destroy(&input); |
79 o_stream_destroy(&output); | |
80 | |
81 if (close(fd_in) < 0) { | |
82 i_error("close(%s) failed: %m", srcpath); | |
83 ret = -1; | |
84 } | |
85 if (close(fd_out) < 0) { | |
86 i_error("close(%s) failed: %m", tmppath); | |
87 ret = -1; | |
88 } | |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
89 return ret < 0 ? -1 : 1; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
90 } |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
91 |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
92 int file_copy(const char *srcpath, const char *destpath, bool try_hardlink) |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
93 { |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
94 int ret; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
95 |
7226
e6693a0ec8e1
Renamed T_FRAME_BEGIN/END to T_BEGIN/END. Removed T_FRAME() macro and
Timo Sirainen <tss@iki.fi>
parents:
7086
diff
changeset
|
96 T_BEGIN { |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
97 const char *tmppath; |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
98 |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
99 tmppath = t_strconcat(destpath, ".tmp", NULL); |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
100 |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
101 ret = file_copy_to_tmp(srcpath, tmppath, try_hardlink); |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
102 if (ret > 0) { |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
103 if (rename(tmppath, destpath) < 0) { |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
104 i_error("rename(%s, %s) failed: %m", |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
105 tmppath, destpath); |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
106 ret = -1; |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
107 } |
4406 | 108 } |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
109 if (ret < 0) |
19136
fefaa6d09a81
Replaced unlink() calls with i_unlink*() wherever possible.
Timo Sirainen <tss@iki.fi>
parents:
18137
diff
changeset
|
110 i_unlink(tmppath); |
7226
e6693a0ec8e1
Renamed T_FRAME_BEGIN/END to T_BEGIN/END. Removed T_FRAME() macro and
Timo Sirainen <tss@iki.fi>
parents:
7086
diff
changeset
|
111 } T_END; |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
112 return ret; |
4406 | 113 } |