Mercurial > dovecot > original-hg > dovecot-1.2
annotate src/lib/file-copy.c @ 9532:00cd9aacd03c HEAD
Updated copyright notices to include year 2010.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 25 Jan 2010 01:18:58 +0200 |
parents | b9faf4db2a9f |
children |
rev | line source |
---|---|
9532
00cd9aacd03c
Updated copyright notices to include year 2010.
Timo Sirainen <tss@iki.fi>
parents:
8590
diff
changeset
|
1 /* Copyright (c) 2006-2010 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) { |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
28 if (unlink(tmppath) < 0 && errno != ENOENT) { |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
29 i_error("unlink(%s) failed: %m", tmppath); |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
30 return -1; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
31 } |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
32 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
|
33 return 1; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
34 } |
4406 | 35 if (errno == ENOENT) |
36 return 0; | |
37 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
|
38 i_error("link(%s, %s) failed: %m", srcpath, tmppath); |
4406 | 39 return -1; |
40 } | |
41 | |
42 /* fallback to manual copying */ | |
43 } | |
44 | |
45 fd_in = open(srcpath, O_RDONLY); | |
46 if (fd_in == -1) { | |
47 if (errno == ENOENT) | |
48 return 0; | |
49 i_error("open(%s) failed: %m", srcpath); | |
50 return -1; | |
51 } | |
52 | |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
53 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
|
54 i_error("fstat(%s) failed: %m", srcpath); |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
55 (void)close(fd_in); |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
56 return -1; |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
57 } |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
58 |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
59 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
|
60 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
|
61 umask(old_umask); |
4406 | 62 if (fd_out == -1) { |
63 i_error("open(%s, O_CREAT) failed: %m", tmppath); | |
64 (void)close(fd_in); | |
65 return -1; | |
66 } | |
4460
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
67 |
80943d914681
Try to preserve file's mode and group when copying it.
Timo Sirainen <tss@iki.fi>
parents:
4428
diff
changeset
|
68 /* 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
|
69 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
|
70 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
|
71 |
6162
896cc473c1f0
Renamed i_stream_create_file() to i_stream_create_fd().
Timo Sirainen <tss@iki.fi>
parents:
6161
diff
changeset
|
72 input = i_stream_create_fd(fd_in, 0, FALSE); |
6161
c62f7ee79446
Split o_stream_create_file() to _create_fd() and _create_fd_file().
Timo Sirainen <tss@iki.fi>
parents:
6142
diff
changeset
|
73 output = o_stream_create_fd_file(fd_out, 0, FALSE); |
4406 | 74 |
75 while ((ret = o_stream_send_istream(output, input)) > 0) ; | |
76 | |
6670
03af6da2ace1
If o_stream_send_istream() fails, log an error.
Timo Sirainen <tss@iki.fi>
parents:
6653
diff
changeset
|
77 if (ret < 0) |
03af6da2ace1
If o_stream_send_istream() fails, log an error.
Timo Sirainen <tss@iki.fi>
parents:
6653
diff
changeset
|
78 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
|
79 |
4406 | 80 i_stream_destroy(&input); |
81 o_stream_destroy(&output); | |
82 | |
83 if (close(fd_in) < 0) { | |
84 i_error("close(%s) failed: %m", srcpath); | |
85 ret = -1; | |
86 } | |
87 if (close(fd_out) < 0) { | |
88 i_error("close(%s) failed: %m", tmppath); | |
89 ret = -1; | |
90 } | |
4428
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
91 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
|
92 } |
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 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
|
95 { |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
96 int ret; |
94dc3f73ffb9
If destination file already existed, we didn't overwrite it with link()
Timo Sirainen <tss@iki.fi>
parents:
4406
diff
changeset
|
97 |
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
|
98 T_BEGIN { |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
99 const char *tmppath; |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
100 |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
101 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
|
102 |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
103 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
|
104 if (ret > 0) { |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
105 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
|
106 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
|
107 tmppath, destpath); |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
108 ret = -1; |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
109 } |
4406 | 110 } |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
111 if (ret < 0) |
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6670
diff
changeset
|
112 (void)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
|
113 } 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
|
114 return ret; |
4406 | 115 } |