Improve rename/copy/reomove API.
* examples/rename.c: Remove. * examples/fcopy.c: New file. * examples/fremove.c: New file. * examples/frename.c: New file. * examples/Makefile.am: Update. * include/mailutils/util.h (mu_rename_file): Add flags. (mu_remove_file): New function. (MU_COPY_OVERWRITE): New flag. * libmailutils/base/renamefile.c: New file. * libmailutils/base/Makefile.am: Add newe file. * libmailutils/base/copyfile.c: Fix error handling. * libmailutils/base/renamefile.c (mu_rename_file): Refuse to proceed if the destination file exists and MU_COPY_OVERWRITE flag is not set * libmailutils/diag/errors (MU_ERR_REMOVE_SOURCE) (MU_ERR_RESTORE_META): New errors * imap4d/rename.c (imap4d_rename): Use mu_rename_file * mh/forw.c: Likewise. * mh/mh_whatnow.c: Likewise. * mh/mhn.c: Likewise. * mh/send.c: Likewise. * include/mailutils/cstr.h (mu_str_count): New proto. * include/mailutils/util.h (mu_file_name_is_safe): New proto. * libmailutils/string/safefilename.c: New file. * libmailutils/string/strcount.c: New file. * libmailutils/string/Makefile.am: Update.
Showing
20 changed files
with
737 additions
and
105 deletions
... | @@ -30,6 +30,9 @@ noinst_PROGRAMS = \ | ... | @@ -30,6 +30,9 @@ noinst_PROGRAMS = \ |
30 | addr\ | 30 | addr\ |
31 | base64\ | 31 | base64\ |
32 | echosrv\ | 32 | echosrv\ |
33 | fcopy\ | ||
34 | fremove\ | ||
35 | frename\ | ||
33 | header\ | 36 | header\ |
34 | http\ | 37 | http\ |
35 | iconv\ | 38 | iconv\ |
... | @@ -44,7 +47,6 @@ noinst_PROGRAMS = \ | ... | @@ -44,7 +47,6 @@ noinst_PROGRAMS = \ |
44 | murun\ | 47 | murun\ |
45 | musocio\ | 48 | musocio\ |
46 | $(NNTPCLIENT)\ | 49 | $(NNTPCLIENT)\ |
47 | rename\ | ||
48 | sa\ | 50 | sa\ |
49 | sfrom | 51 | sfrom |
50 | 52 | ... | ... |
1 | #include <mailutils/mailutils.h> | 1 | #include <mailutils/mailutils.h> |
2 | 2 | ||
3 | int copy_option; | ||
4 | int owner_option; | 3 | int owner_option; |
5 | int mode_option; | 4 | int mode_option; |
5 | int force_option; | ||
6 | int deref_option; | ||
6 | 7 | ||
7 | static struct mu_option rename_options[] = { | 8 | static struct mu_option copy_options[] = { |
8 | { "copy", 'c', NULL, MU_OPTION_DEFAULT, | ||
9 | "copy the file", | ||
10 | mu_c_bool, ©_option }, | ||
11 | { "owner", 'u', NULL, MU_OPTION_DEFAULT, | 9 | { "owner", 'u', NULL, MU_OPTION_DEFAULT, |
12 | "copy ownership", | 10 | "copy ownership", |
13 | mu_c_bool, &owner_option }, | 11 | mu_c_bool, &owner_option }, |
14 | { "mode", 'm', NULL, MU_OPTION_DEFAULT, | 12 | { "mode", 'm', NULL, MU_OPTION_DEFAULT, |
15 | "copy mode", | 13 | "copy mode", |
16 | mu_c_bool, &mode_option }, | 14 | mu_c_bool, &mode_option }, |
15 | { "force", 'f', NULL, MU_OPTION_DEFAULT, | ||
16 | "force overwriting the destination file if it exists", | ||
17 | mu_c_bool, &force_option }, | ||
18 | { "overwrite", 0, NULL, MU_OPTION_ALIAS }, | ||
19 | { "dereference", 'h', NULL, MU_OPTION_DEFAULT, | ||
20 | "dereference symbolic links", | ||
21 | mu_c_bool, &deref_option }, | ||
17 | MU_OPTION_END | 22 | MU_OPTION_END |
18 | }, *options[] = { rename_options, NULL }; | 23 | }, *options[] = { copy_options, NULL }; |
19 | 24 | ||
20 | struct mu_cli_setup cli = { | 25 | struct mu_cli_setup cli = { |
21 | options, | 26 | options, |
22 | NULL, | 27 | NULL, |
23 | "copy or rename file", | 28 | "copy file", |
24 | "SRC DST" | 29 | "SRC DST" |
25 | }; | 30 | }; |
26 | 31 | ||
... | @@ -33,6 +38,7 @@ int | ... | @@ -33,6 +38,7 @@ int |
33 | main (int argc, char **argv) | 38 | main (int argc, char **argv) |
34 | { | 39 | { |
35 | int rc; | 40 | int rc; |
41 | int flags; | ||
36 | 42 | ||
37 | mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); | 43 | mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); |
38 | 44 | ||
... | @@ -42,17 +48,14 @@ main (int argc, char **argv) | ... | @@ -42,17 +48,14 @@ main (int argc, char **argv) |
42 | return 1; | 48 | return 1; |
43 | } | 49 | } |
44 | 50 | ||
45 | if (copy_option) | 51 | flags = (owner_option ? MU_COPY_OWNER : 0) |
46 | { | 52 | | (mode_option ? MU_COPY_MODE : 0) |
47 | int flags = (owner_option ? MU_COPY_OWNER : 0) | 53 | | (force_option ? MU_COPY_OVERWRITE : 0) |
48 | | (mode_option ? MU_COPY_MODE : 0); | 54 | | (deref_option ? MU_COPY_DEREF : 0); |
49 | rc = mu_copy_file (argv[0], argv[1], flags); | 55 | rc = mu_copy_file (argv[0], argv[1], flags); |
50 | } | ||
51 | else | ||
52 | rc = mu_rename_file (argv[0], argv[1]); | ||
53 | 56 | ||
54 | if (rc) | 57 | if (rc) |
55 | mu_diag_funcall (MU_DIAG_ERROR, "mu_rename_file", NULL, rc); | 58 | mu_diag_funcall (MU_DIAG_ERROR, "mu_copy_file", NULL, rc); |
56 | 59 | ||
57 | return !!rc; | 60 | return !!rc; |
58 | } | 61 | } | ... | ... |
examples/fremove.c
0 → 100644
1 | #include <mailutils/mailutils.h> | ||
2 | |||
3 | int owner_option; | ||
4 | int mode_option; | ||
5 | int force_option; | ||
6 | |||
7 | static struct mu_option *options[] = { NULL }; | ||
8 | |||
9 | struct mu_cli_setup cli = { | ||
10 | options, | ||
11 | NULL, | ||
12 | "delete file", | ||
13 | "FILE" | ||
14 | }; | ||
15 | |||
16 | static char *capa[] = { | ||
17 | "debug", | ||
18 | NULL | ||
19 | }; | ||
20 | |||
21 | int | ||
22 | main (int argc, char **argv) | ||
23 | { | ||
24 | int rc; | ||
25 | |||
26 | mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); | ||
27 | |||
28 | if (argc != 1) | ||
29 | { | ||
30 | mu_error ("wrong number of arguments"); | ||
31 | return 1; | ||
32 | } | ||
33 | |||
34 | if (!mu_file_name_is_safe (argv[0]) | ||
35 | || (argv[0][0] == '/' && mu_str_count (argv[0], '/') < 2)) | ||
36 | { | ||
37 | mu_error ("unsafe file name"); | ||
38 | return 1; | ||
39 | } | ||
40 | |||
41 | rc = mu_remove_file (argv[0]); | ||
42 | |||
43 | if (rc) | ||
44 | mu_diag_funcall (MU_DIAG_ERROR, "mu_remove_file", NULL, rc); | ||
45 | |||
46 | return !!rc; | ||
47 | } | ||
48 | |||
49 |
examples/frename.c
0 → 100644
1 | #include <mailutils/mailutils.h> | ||
2 | |||
3 | int force_option; | ||
4 | |||
5 | static struct mu_option rename_options[] = { | ||
6 | { "force", 'f', NULL, MU_OPTION_DEFAULT, | ||
7 | "force overwriting the destination file if it exists", | ||
8 | mu_c_bool, &force_option }, | ||
9 | { "overwrite", 0, NULL, MU_OPTION_ALIAS }, | ||
10 | MU_OPTION_END | ||
11 | }, *options[] = { rename_options, NULL }; | ||
12 | |||
13 | struct mu_cli_setup cli = { | ||
14 | options, | ||
15 | NULL, | ||
16 | "rename file", | ||
17 | "SRC DST" | ||
18 | }; | ||
19 | |||
20 | static char *capa[] = { | ||
21 | "debug", | ||
22 | NULL | ||
23 | }; | ||
24 | |||
25 | int | ||
26 | main (int argc, char **argv) | ||
27 | { | ||
28 | int rc; | ||
29 | |||
30 | mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); | ||
31 | |||
32 | if (argc != 2) | ||
33 | { | ||
34 | mu_error ("wrong number of arguments"); | ||
35 | return 1; | ||
36 | } | ||
37 | |||
38 | if (!mu_file_name_is_safe (argv[0]) | ||
39 | || (argv[0][0] == '/' && mu_str_count (argv[0], '/') < 2)) | ||
40 | { | ||
41 | mu_error ("%s: unsafe file name", argv[0]); | ||
42 | return 1; | ||
43 | } | ||
44 | if (!mu_file_name_is_safe (argv[1]) | ||
45 | || (argv[1][0] == '/' && mu_str_count (argv[1], '/') < 2)) | ||
46 | { | ||
47 | mu_error ("%sunsafe file name", argv[0]); | ||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | rc = mu_rename_file (argv[0], argv[1], force_option ? MU_COPY_OVERWRITE : 0); | ||
52 | |||
53 | if (rc) | ||
54 | mu_diag_funcall (MU_DIAG_ERROR, "mu_rename_file", NULL, rc); | ||
55 | |||
56 | return !!rc; | ||
57 | } | ||
58 | |||
59 |
... | @@ -125,8 +125,8 @@ imap4d_rename (struct imap4d_session *session, | ... | @@ -125,8 +125,8 @@ imap4d_rename (struct imap4d_session *session, |
125 | if (!newname) | 125 | if (!newname) |
126 | return io_completion_response (command, RESP_NO, "Permission denied"); | 126 | return io_completion_response (command, RESP_NO, "Permission denied"); |
127 | 127 | ||
128 | /* It is an error to attempt to rename from a mailbox name that already | 128 | /* It is an error to attempt to rename from a mailbox name that does not |
129 | exist. */ | 129 | exist or to a mailbox name that already exists. */ |
130 | if (stat (newname, &newst) == 0) | 130 | if (stat (newname, &newst) == 0) |
131 | { | 131 | { |
132 | /* FIXME: What if it's a maildir?!? */ | 132 | /* FIXME: What if it's a maildir?!? */ |
... | @@ -216,9 +216,26 @@ imap4d_rename (struct imap4d_session *session, | ... | @@ -216,9 +216,26 @@ imap4d_rename (struct imap4d_session *session, |
216 | } | 216 | } |
217 | else | 217 | else |
218 | { | 218 | { |
219 | if (rename (oldname, newname) != 0) | 219 | rc = mu_rename_file (oldname, newname, 0); |
220 | if (rc) | ||
220 | { | 221 | { |
221 | mu_diag_funcall (MU_DIAG_ERROR, "rename", oldname, errno); | 222 | switch (rc) |
223 | { | ||
224 | case MU_ERR_REMOVE_SOURCE: | ||
225 | mu_error (_("failed to remove source mailbox after moving %s to %s"), | ||
226 | oldname, newname); | ||
227 | break; | ||
228 | |||
229 | case MU_ERR_RESTORE_META: | ||
230 | mu_error (_("failed to restore mailbox ownership/modes after moving %s to %s"), | ||
231 | oldname, newname); | ||
232 | break; | ||
233 | |||
234 | default: | ||
235 | mu_error (_("error renaming mailbox %s to %s: %s"), | ||
236 | oldname, newname, mu_strerror (rc)); | ||
237 | } | ||
238 | |||
222 | rc = RESP_NO; | 239 | rc = RESP_NO; |
223 | msg = "Failed"; | 240 | msg = "Failed"; |
224 | } | 241 | } | ... | ... |
... | @@ -45,6 +45,8 @@ char *mu_str_skip_cset_comp (const char *str, const char *cset); | ... | @@ -45,6 +45,8 @@ char *mu_str_skip_cset_comp (const char *str, const char *cset); |
45 | char *mu_str_stripws (char *string); | 45 | char *mu_str_stripws (char *string); |
46 | 46 | ||
47 | int mu_string_split (const char *string, char *delim, mu_list_t list); | 47 | int mu_string_split (const char *string, char *delim, mu_list_t list); |
48 | |||
49 | size_t mu_str_count (char const *str, int chr); | ||
48 | 50 | ||
49 | #ifdef __cplusplus | 51 | #ifdef __cplusplus |
50 | } | 52 | } | ... | ... |
... | @@ -140,8 +140,6 @@ struct mu_param | ... | @@ -140,8 +140,6 @@ struct mu_param |
140 | char *name; | 140 | char *name; |
141 | char *value; | 141 | char *value; |
142 | }; | 142 | }; |
143 | |||
144 | |||
145 | 143 | ||
146 | int mu_content_type_parse (const char *input, mu_content_type_t *retct); | 144 | int mu_content_type_parse (const char *input, mu_content_type_t *retct); |
147 | void mu_content_type_destroy (mu_content_type_t *pptr); | 145 | void mu_content_type_destroy (mu_content_type_t *pptr); |
... | @@ -207,17 +205,23 @@ int mu_str_to_c (char const *string, mu_c_type_t type, void *tgt, | ... | @@ -207,17 +205,23 @@ int mu_str_to_c (char const *string, mu_c_type_t type, void *tgt, |
207 | /* -------------------------- */ | 205 | /* -------------------------- */ |
208 | /* Safe file copy and rename */ | 206 | /* Safe file copy and rename */ |
209 | /* -------------------------- */ | 207 | /* -------------------------- */ |
210 | #define MU_COPY_MODE 0x01 | 208 | /* Bits for the flags argument of mu_copy_file and mu_rename_file. The |
211 | #define MU_COPY_OWNER 0x02 | 209 | MU_COPY_OVERWRITE is valid for both calls. The rest is for mu_copy_file |
212 | #define MU_COPY_SYMLINK 0x04 | 210 | only */ |
213 | #define MU_COPY_FORCE 0x08 | 211 | #define MU_COPY_OVERWRITE 0x01 /* Overwrite destination file, if it exists */ |
212 | #define MU_COPY_MODE 0x02 /* Preserve file mode */ | ||
213 | #define MU_COPY_OWNER 0x04 /* Preserve file ownership */ | ||
214 | #define MU_COPY_DEREF 0x08 /* Dereference the source file */ | ||
214 | 215 | ||
215 | int mu_copy_file (const char *srcpath, const char *dstpath, int flags); | 216 | int mu_copy_file (const char *srcpath, const char *dstpath, int flags); |
216 | int mu_rename_file (const char *oldpath, const char *newpath); | 217 | int mu_rename_file (const char *oldpath, const char *newpath, int flags); |
218 | int mu_remove_file (const char *path); | ||
217 | 219 | ||
218 | /* ----------------------- */ | 220 | /* ----------------------- */ |
219 | /* Assorted functions. */ | 221 | /* Assorted functions. */ |
220 | /* ----------------------- */ | 222 | /* ----------------------- */ |
223 | int mu_file_name_is_safe (char const *str); | ||
224 | |||
221 | int mu_getmaxfd (void); | 225 | int mu_getmaxfd (void); |
222 | /* Get the host name, doing a gethostbyname() if possible. */ | 226 | /* Get the host name, doing a gethostbyname() if possible. */ |
223 | int mu_get_host_name (char **host); | 227 | int mu_get_host_name (char **host); | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
1 | #include <config.h> | 17 | #include <config.h> |
2 | #include <sys/types.h> | 18 | #include <sys/types.h> |
3 | #include <sys/stat.h> | 19 | #include <sys/stat.h> |
... | @@ -16,13 +32,24 @@ static int copy_regular_file (const char *srcpath, const char *dstpath, | ... | @@ -16,13 +32,24 @@ static int copy_regular_file (const char *srcpath, const char *dstpath, |
16 | static int copy_symlink (const char *srcpath, const char *dstpath); | 32 | static int copy_symlink (const char *srcpath, const char *dstpath); |
17 | static int copy_dir (const char *srcpath, const char *dstpath, int flags); | 33 | static int copy_dir (const char *srcpath, const char *dstpath, int flags); |
18 | 34 | ||
35 | /* Copy SRCPATH to DSTPATH. SRCPATH can be any kind of file. If it is | ||
36 | a directory, its content will be copied recursively. | ||
37 | |||
38 | FLAGS: | ||
39 | |||
40 | MU_COPY_OVERWRITE Overwrite destination file, if it exists. | ||
41 | MU_COPY_MODE Preserve file mode | ||
42 | MU_COPY_OWNER Preserve file ownership | ||
43 | MU_COPY_DEREF Dereference symbolic links: operate on files they | ||
44 | refer to. | ||
45 | */ | ||
19 | int | 46 | int |
20 | mu_copy_file (const char *srcpath, const char *dstpath, int flags) | 47 | mu_copy_file (const char *srcpath, const char *dstpath, int flags) |
21 | { | 48 | { |
22 | int rc = 0; | 49 | int rc = 0; |
23 | struct stat st; | 50 | struct stat st; |
24 | 51 | ||
25 | if (((flags & MU_COPY_SYMLINK) ? lstat : stat) (srcpath, &st)) | 52 | if (((flags & MU_COPY_DEREF) ? stat : lstat) (srcpath, &st)) |
26 | { | 53 | { |
27 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | 54 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, |
28 | (_("can't stat file %s: %s"), | 55 | (_("can't stat file %s: %s"), |
... | @@ -30,6 +57,23 @@ mu_copy_file (const char *srcpath, const char *dstpath, int flags) | ... | @@ -30,6 +57,23 @@ mu_copy_file (const char *srcpath, const char *dstpath, int flags) |
30 | return errno; | 57 | return errno; |
31 | } | 58 | } |
32 | 59 | ||
60 | if (access (dstpath, F_OK) == 0) | ||
61 | { | ||
62 | if (flags & MU_COPY_OVERWRITE) | ||
63 | { | ||
64 | rc = mu_remove_file (dstpath); | ||
65 | if (rc) | ||
66 | { | ||
67 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
68 | (_("can't remove destination %s: %s"), | ||
69 | dstpath, mu_strerror (rc))); | ||
70 | return rc; | ||
71 | } | ||
72 | } | ||
73 | else | ||
74 | return EEXIST; | ||
75 | } | ||
76 | |||
33 | switch (st.st_mode & S_IFMT) | 77 | switch (st.st_mode & S_IFMT) |
34 | { | 78 | { |
35 | case S_IFREG: | 79 | case S_IFREG: |
... | @@ -37,11 +81,9 @@ mu_copy_file (const char *srcpath, const char *dstpath, int flags) | ... | @@ -37,11 +81,9 @@ mu_copy_file (const char *srcpath, const char *dstpath, int flags) |
37 | 81 | ||
38 | case S_IFLNK: | 82 | case S_IFLNK: |
39 | return copy_symlink (srcpath, dstpath); | 83 | return copy_symlink (srcpath, dstpath); |
40 | break; | ||
41 | 84 | ||
42 | case S_IFDIR: | 85 | case S_IFDIR: |
43 | return copy_dir (srcpath, dstpath, flags); | 86 | return copy_dir (srcpath, dstpath, flags); |
44 | break; | ||
45 | 87 | ||
46 | case S_IFBLK: | 88 | case S_IFBLK: |
47 | case S_IFCHR: | 89 | case S_IFCHR: |
... | @@ -123,16 +165,16 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, | ... | @@ -123,16 +165,16 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, |
123 | { | 165 | { |
124 | if (fchmod ((int) trans[0], mode)) | 166 | if (fchmod ((int) trans[0], mode)) |
125 | { | 167 | { |
126 | rc = errno; | ||
127 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | 168 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, |
128 | (_("%s: cannot chmod: %s"), | 169 | (_("%s: cannot chmod: %s"), |
129 | dstpath, mu_strerror (rc))); | 170 | dstpath, mu_strerror (errno))); |
171 | rc = MU_ERR_RESTORE_META; | ||
130 | } | 172 | } |
131 | else if (flags & MU_COPY_OWNER) | 173 | else if (flags & MU_COPY_OWNER) |
132 | { | 174 | { |
133 | uid_t uid; | 175 | uid_t uid; |
134 | gid_t gid; | 176 | gid_t gid; |
135 | 177 | ||
136 | if (getuid () == 0) | 178 | if (getuid () == 0) |
137 | { | 179 | { |
138 | uid = st->st_uid; | 180 | uid = st->st_uid; |
... | @@ -153,13 +195,13 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, | ... | @@ -153,13 +195,13 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, |
153 | { | 195 | { |
154 | if (fchown ((int) trans[0], uid, gid)) | 196 | if (fchown ((int) trans[0], uid, gid)) |
155 | { | 197 | { |
156 | rc = errno; | ||
157 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | 198 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, |
158 | (_("%s: cannot chown to %lu.%lu: %s"), | 199 | (_("%s: cannot chown to %lu.%lu: %s"), |
159 | dstpath, | 200 | dstpath, |
160 | (unsigned long) uid, | 201 | (unsigned long) uid, |
161 | (unsigned long) gid, | 202 | (unsigned long) gid, |
162 | mu_strerror (rc))); | 203 | mu_strerror (errno))); |
204 | rc = MU_ERR_RESTORE_META; | ||
163 | } | 205 | } |
164 | } | 206 | } |
165 | } | 207 | } |
... | @@ -212,9 +254,8 @@ copy_dir (const char *srcpath, const char *dstpath, int flags) | ... | @@ -212,9 +254,8 @@ copy_dir (const char *srcpath, const char *dstpath, int flags) |
212 | { | 254 | { |
213 | DIR *dirp; | 255 | DIR *dirp; |
214 | struct dirent *dp; | 256 | struct dirent *dp; |
215 | struct stat st, st1; | 257 | struct stat st; |
216 | int rc; | 258 | int rc; |
217 | int create = 0; | ||
218 | mode_t mode, mask; | 259 | mode_t mode, mask; |
219 | 260 | ||
220 | if (stat (srcpath, &st)) | 261 | if (stat (srcpath, &st)) |
... | @@ -225,67 +266,28 @@ copy_dir (const char *srcpath, const char *dstpath, int flags) | ... | @@ -225,67 +266,28 @@ copy_dir (const char *srcpath, const char *dstpath, int flags) |
225 | return errno; | 266 | return errno; |
226 | } | 267 | } |
227 | 268 | ||
228 | if (stat (dstpath, &st1)) | ||
229 | { | ||
230 | if (errno == ENOENT) | ||
231 | create = 1; | ||
232 | else | ||
233 | { | ||
234 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
235 | (_("can't stat directory %s: %s"), | ||
236 | dstpath, mu_strerror (errno))); | ||
237 | return errno; | ||
238 | } | ||
239 | } | ||
240 | else if (!S_ISDIR (st1.st_mode)) | ||
241 | { | ||
242 | if (flags & MU_COPY_FORCE) | ||
243 | { | ||
244 | if (unlink (dstpath)) | ||
245 | { | ||
246 | rc = errno; | ||
247 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
248 | (_("%s is not a directory and cannot be unlinked: %s"), | ||
249 | dstpath, mu_strerror (rc))); | ||
250 | return rc; | ||
251 | } | ||
252 | create = 1; | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
257 | (_("%s is not a directory"), | ||
258 | dstpath)); | ||
259 | return EEXIST; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | mask = umask (077); | 269 | mask = umask (077); |
264 | mode = ((flags & MU_COPY_MODE) ? st.st_mode : (0777 & ~mask)) & 0777; | 270 | mode = ((flags & MU_COPY_MODE) ? st.st_mode : (0777 & ~mask)) & 0777; |
265 | 271 | ||
266 | if (create) | 272 | rc = mkdir (dstpath, 0700); |
267 | { | 273 | umask (mask); |
268 | rc = mkdir (dstpath, 0700); | ||
269 | umask (mask); | ||
270 | 274 | ||
271 | if (rc) | 275 | if (rc) |
272 | { | 276 | { |
273 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | 277 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, |
274 | (_("can't create directory %s: %s"), | 278 | (_("can't create directory %s: %s"), |
275 | dstpath, mu_strerror (errno))); | 279 | dstpath, mu_strerror (errno))); |
276 | return errno; | 280 | return errno; |
277 | } | ||
278 | } | 281 | } |
279 | else | ||
280 | umask (mask); | ||
281 | 282 | ||
282 | dirp = opendir (srcpath); | 283 | dirp = opendir (srcpath); |
283 | if (dirp == NULL) | 284 | if (dirp == NULL) |
284 | { | 285 | { |
285 | mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR, | 286 | rc = errno; |
287 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
286 | ("cannot open directory %s: %s", | 288 | ("cannot open directory %s: %s", |
287 | srcpath, mu_strerror (errno))); | 289 | srcpath, mu_strerror (errno))); |
288 | return 1; | 290 | return rc; |
289 | } | 291 | } |
290 | 292 | ||
291 | while ((dp = readdir (dirp))) | 293 | while ((dp = readdir (dirp))) | ... | ... |
libmailutils/base/removefile.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <unistd.h> | ||
20 | #include <sys/types.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <dirent.h> | ||
23 | #include <mailutils/stream.h> | ||
24 | #include <mailutils/util.h> | ||
25 | #include <mailutils/diag.h> | ||
26 | #include <mailutils/error.h> | ||
27 | #include <mailutils/errno.h> | ||
28 | #include <mailutils/list.h> | ||
29 | #include <mailutils/iterator.h> | ||
30 | #include <mailutils/nls.h> | ||
31 | |||
32 | static int removedir (const char *path); | ||
33 | |||
34 | int | ||
35 | mu_remove_file (const char *path) | ||
36 | { | ||
37 | int rc = 0; | ||
38 | struct stat st; | ||
39 | |||
40 | if (stat (path, &st)) | ||
41 | { | ||
42 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
43 | (_("can't stat file %s: %s"), | ||
44 | path, mu_strerror (errno))); | ||
45 | return errno; | ||
46 | } | ||
47 | |||
48 | if (S_ISDIR (st.st_mode)) | ||
49 | rc = removedir (path); | ||
50 | else if (unlink (path)) | ||
51 | { | ||
52 | rc = errno; | ||
53 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
54 | (_("can't unlink file %s: %s"), | ||
55 | path, mu_strerror (rc))); | ||
56 | } | ||
57 | |||
58 | return rc; | ||
59 | } | ||
60 | |||
61 | struct nameent | ||
62 | { | ||
63 | int isdir; | ||
64 | char name[1]; | ||
65 | }; | ||
66 | |||
67 | static int | ||
68 | name_add (mu_list_t list, char const *name) | ||
69 | { | ||
70 | int rc; | ||
71 | size_t len = strlen (name); | ||
72 | struct nameent *ent = malloc (sizeof (*ent) + len); | ||
73 | if (!ent) | ||
74 | { | ||
75 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
76 | ("%s", mu_strerror (errno))); | ||
77 | return 1; | ||
78 | } | ||
79 | ent->isdir = -1; | ||
80 | strcpy (ent->name, name); | ||
81 | rc = mu_list_append (list, ent); | ||
82 | if (rc) | ||
83 | { | ||
84 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
85 | ("mu_list_append: %s", mu_strerror (rc))); | ||
86 | free (ent); | ||
87 | } | ||
88 | |||
89 | return rc; | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | lsdir (const char *path, mu_list_t list) | ||
94 | { | ||
95 | DIR *dirp; | ||
96 | struct dirent *dp; | ||
97 | int rc = 0; | ||
98 | |||
99 | dirp = opendir (path); | ||
100 | if (dirp == NULL) | ||
101 | { | ||
102 | rc = errno; | ||
103 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
104 | ("cannot open directory %s: %s", | ||
105 | path, mu_strerror (errno))); | ||
106 | return rc; | ||
107 | } | ||
108 | |||
109 | while ((dp = readdir (dirp))) | ||
110 | { | ||
111 | char const *ename = dp->d_name; | ||
112 | char *filename; | ||
113 | |||
114 | if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0) | ||
115 | continue; | ||
116 | |||
117 | filename = mu_make_file_name (path, ename); | ||
118 | if (!filename) | ||
119 | { | ||
120 | rc = errno; | ||
121 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
122 | ("%s: can't create file name: %s", | ||
123 | path, mu_strerror (errno))); | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | rc = name_add (list, filename); | ||
128 | free (filename); | ||
129 | if (rc) | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | closedir (dirp); | ||
134 | |||
135 | return rc; | ||
136 | } | ||
137 | |||
138 | static int | ||
139 | namecmp (const void *a, const void *b) | ||
140 | { | ||
141 | struct nameent const *enta = a; | ||
142 | struct nameent const *entb = b; | ||
143 | int d = enta->isdir - entb->isdir; | ||
144 | if (d) | ||
145 | return d; | ||
146 | return strcmp (entb->name, enta->name); | ||
147 | } | ||
148 | |||
149 | static int | ||
150 | check_parent_access (const char *path) | ||
151 | { | ||
152 | int rc; | ||
153 | char *name, *p; | ||
154 | |||
155 | name = strdup (path); | ||
156 | if (!name) | ||
157 | return errno; | ||
158 | p = strrchr (name, '/'); | ||
159 | if (p) | ||
160 | *p = 0; | ||
161 | else | ||
162 | strcpy (name, "."); | ||
163 | rc = access (name, R_OK|W_OK|X_OK); | ||
164 | free (name); | ||
165 | if (rc) | ||
166 | { | ||
167 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
168 | (_("not enough privileges to remove files from %s"), | ||
169 | name)); | ||
170 | return EACCES; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int | ||
177 | removedir (const char *path) | ||
178 | { | ||
179 | int rc; | ||
180 | struct stat st; | ||
181 | mu_list_t namelist; | ||
182 | mu_iterator_t itr; | ||
183 | struct nameent *ent; | ||
184 | |||
185 | rc = check_parent_access (path); | ||
186 | if (rc) | ||
187 | return rc; | ||
188 | |||
189 | rc = mu_list_create (&namelist); | ||
190 | if (rc) | ||
191 | { | ||
192 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
193 | ("mu_list_create: %s", mu_strerror (rc))); | ||
194 | return rc; | ||
195 | } | ||
196 | mu_list_set_destroy_item (namelist, mu_list_free_item); | ||
197 | mu_list_set_comparator (namelist, namecmp); | ||
198 | |||
199 | rc = name_add (namelist, path); | ||
200 | if (rc) | ||
201 | { | ||
202 | mu_list_destroy (&namelist); | ||
203 | return rc; | ||
204 | } | ||
205 | |||
206 | rc = mu_list_get_iterator (namelist, &itr); | ||
207 | if (rc) | ||
208 | { | ||
209 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
210 | ("mu_list_get_iterator: %s", mu_strerror (rc))); | ||
211 | mu_list_destroy (&namelist); | ||
212 | return rc; | ||
213 | } | ||
214 | |||
215 | for (mu_iterator_first (itr); | ||
216 | !mu_iterator_is_done (itr); | ||
217 | mu_iterator_next (itr)) | ||
218 | { | ||
219 | mu_iterator_current (itr, (void **)&ent); | ||
220 | |||
221 | if (lstat (ent->name, &st)) | ||
222 | { | ||
223 | rc = errno; | ||
224 | if (rc == ENOENT) | ||
225 | continue; | ||
226 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
227 | (_("can't lstat file %s: %s"), | ||
228 | ent->name, mu_strerror (rc))); | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | if (S_ISDIR (st.st_mode)) | ||
233 | { | ||
234 | ent->isdir = 1; | ||
235 | if (access (ent->name, R_OK|W_OK|X_OK)) | ||
236 | { | ||
237 | rc = EACCES; | ||
238 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
239 | (_("not enough privileges to remove files from %s"), | ||
240 | ent->name)); | ||
241 | } | ||
242 | else | ||
243 | rc = lsdir (ent->name, namelist); | ||
244 | if (rc) | ||
245 | break; | ||
246 | } | ||
247 | else | ||
248 | ent->isdir = 0; | ||
249 | } | ||
250 | |||
251 | if (rc == 0) | ||
252 | { | ||
253 | mu_list_sort (namelist, namecmp); | ||
254 | |||
255 | for (mu_iterator_first (itr); | ||
256 | !mu_iterator_is_done (itr); | ||
257 | mu_iterator_next (itr)) | ||
258 | { | ||
259 | mu_iterator_current (itr, (void **)&ent); | ||
260 | rc = (ent->isdir ? rmdir : unlink) (ent->name); | ||
261 | if (rc) | ||
262 | { | ||
263 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | ||
264 | (_("can't remove %s: %s"), | ||
265 | ent->name, mu_strerror (rc))); | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | mu_iterator_destroy (&itr); | ||
270 | mu_list_destroy (&namelist); | ||
271 | |||
272 | return rc; | ||
273 | } | ||
274 | |||
275 |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
1 | #include <config.h> | 17 | #include <config.h> |
2 | #include <stdio.h> | 18 | #include <stdio.h> |
3 | #include <unistd.h> | 19 | #include <unistd.h> |
20 | #include <sys/stat.h> | ||
4 | #include <mailutils/stream.h> | 21 | #include <mailutils/stream.h> |
5 | #include <mailutils/util.h> | 22 | #include <mailutils/util.h> |
6 | #include <mailutils/diag.h> | 23 | #include <mailutils/diag.h> |
... | @@ -8,10 +25,36 @@ | ... | @@ -8,10 +25,36 @@ |
8 | #include <mailutils/errno.h> | 25 | #include <mailutils/errno.h> |
9 | #include <mailutils/nls.h> | 26 | #include <mailutils/nls.h> |
10 | 27 | ||
28 | /* Rename file OLDPATH to NEWPATH. Prefer rename(2), unless OLDPATH | ||
29 | and NEWPATH reside on different devices. In the latter case, fall | ||
30 | back to recursive copying. | ||
31 | |||
32 | FLAGS controls what to do if NEWPATH exists. If it has MU_COPY_OVERWRITE | ||
33 | bit set, the NEWPATH will be overwritten (if possible, atomically). | ||
34 | Otherwise EEXIST will be returned. | ||
35 | */ | ||
11 | int | 36 | int |
12 | mu_rename_file (const char *oldpath, const char *newpath) | 37 | mu_rename_file (const char *oldpath, const char *newpath, int flags) |
13 | { | 38 | { |
14 | int rc; | 39 | int rc; |
40 | struct stat st; | ||
41 | |||
42 | if (access (oldpath, F_OK)) | ||
43 | return errno; | ||
44 | |||
45 | if (stat (newpath, &st) == 0) | ||
46 | { | ||
47 | if (flags & MU_COPY_OVERWRITE) | ||
48 | { | ||
49 | if (S_ISDIR (st.st_mode)) | ||
50 | { | ||
51 | if (mu_remove_file (newpath)) | ||
52 | return MU_ERR_REMOVE_DEST; | ||
53 | } | ||
54 | } | ||
55 | else | ||
56 | return EEXIST; | ||
57 | } | ||
15 | 58 | ||
16 | if (rename (oldpath, newpath) == 0) | 59 | if (rename (oldpath, newpath) == 0) |
17 | return 0; | 60 | return 0; |
... | @@ -24,16 +67,20 @@ mu_rename_file (const char *oldpath, const char *newpath) | ... | @@ -24,16 +67,20 @@ mu_rename_file (const char *oldpath, const char *newpath) |
24 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_TRACE1, | 67 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_TRACE1, |
25 | (_("attempting copy"))); | 68 | (_("attempting copy"))); |
26 | 69 | ||
27 | rc = mu_copy_file (oldpath, newpath, MU_COPY_MODE|MU_COPY_OWNER); | 70 | rc = mu_copy_file (oldpath, newpath, flags|MU_COPY_MODE|MU_COPY_OWNER); |
28 | if (rc == 0) | 71 | if (rc == 0) |
29 | { | 72 | { |
30 | if (unlink (oldpath)) | 73 | rc = mu_remove_file (oldpath); |
74 | if (rc) | ||
31 | { | 75 | { |
32 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, | 76 | mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, |
33 | (_("copied %s to %s, but failed to remove the source: %s"), | 77 | (_("copied %s to %s, but failed to remove the source: %s"), |
34 | oldpath, newpath, mu_strerror (errno))); | 78 | oldpath, newpath, mu_strerror (rc))); |
79 | rc = MU_ERR_REMOVE_SOURCE; | ||
35 | } | 80 | } |
36 | } | 81 | } |
37 | } | 82 | } |
83 | else | ||
84 | rc = errno; | ||
38 | return rc; | 85 | return rc; |
39 | } | 86 | } | ... | ... |
... | @@ -125,3 +125,7 @@ MU_ERR_PERM_DIR_IWOTH _("File in world writable directory") | ... | @@ -125,3 +125,7 @@ MU_ERR_PERM_DIR_IWOTH _("File in world writable directory") |
125 | MU_ERR_DISABLED _("Requested feature disabled in configuration") | 125 | MU_ERR_DISABLED _("Requested feature disabled in configuration") |
126 | 126 | ||
127 | MU_ERR_FORMAT _("Error in format string") | 127 | MU_ERR_FORMAT _("Error in format string") |
128 | |||
129 | MU_ERR_REMOVE_SOURCE _("Failed to remove source file") | ||
130 | MU_ERR_REMOVE_DEST _("Failed to remove destination file") | ||
131 | MU_ERR_RESTORE_META _("Failed to restore ownership or mode") | ... | ... |
... | @@ -24,8 +24,10 @@ libstring_la_SOURCES = \ | ... | @@ -24,8 +24,10 @@ libstring_la_SOURCES = \ |
24 | cstrlower.c\ | 24 | cstrlower.c\ |
25 | cstrupper.c\ | 25 | cstrupper.c\ |
26 | hexstr.c\ | 26 | hexstr.c\ |
27 | safefilename.c\ | ||
27 | stpcpy.c\ | 28 | stpcpy.c\ |
28 | str_to_c.c\ | 29 | str_to_c.c\ |
30 | strcount.c\ | ||
29 | strltrim.c\ | 31 | strltrim.c\ |
30 | strskip.c\ | 32 | strskip.c\ |
31 | stripws.c\ | 33 | stripws.c\ | ... | ... |
libmailutils/string/safefilename.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <mailutils/util.h> | ||
19 | |||
20 | /* Return 1 if file name STR is safe, or 0 otherwise. | ||
21 | The name is not safe if it begins with .. or contains /../ | ||
22 | */ | ||
23 | int | ||
24 | mu_file_name_is_safe (char const *str) | ||
25 | { | ||
26 | enum { st_init, st_slash, st_dot, st_dotdot } state; | ||
27 | unsigned char c; | ||
28 | int consume = 0; | ||
29 | |||
30 | if (!str) | ||
31 | return 0; | ||
32 | |||
33 | state = (*str == '.') ? st_dot : st_init; | ||
34 | |||
35 | while ((c = *str++) != 0) | ||
36 | { | ||
37 | if (consume) | ||
38 | consume--; | ||
39 | else if (c < 0xc0) | ||
40 | { | ||
41 | switch (state) | ||
42 | { | ||
43 | case st_init: | ||
44 | if (c == '/') | ||
45 | state = st_slash; | ||
46 | break; | ||
47 | |||
48 | case st_slash: | ||
49 | if (c == '.') | ||
50 | state = st_dot; | ||
51 | else if (c != '/') | ||
52 | state = st_init; | ||
53 | break; | ||
54 | |||
55 | case st_dot: | ||
56 | if (c == '.') | ||
57 | state = st_dotdot; | ||
58 | else if (c == '/') | ||
59 | state = st_slash; | ||
60 | else | ||
61 | state = st_init; | ||
62 | break; | ||
63 | |||
64 | case st_dotdot: | ||
65 | if (c == '/') | ||
66 | return 0; | ||
67 | else | ||
68 | state = st_init; | ||
69 | break; | ||
70 | } | ||
71 | } | ||
72 | else if (c & 0xc0) | ||
73 | consume = 1; | ||
74 | else if (c & 0xe0) | ||
75 | consume = 2; | ||
76 | else if (c & 0xf0) | ||
77 | consume = 3; | ||
78 | } | ||
79 | |||
80 | if (state == st_dotdot) | ||
81 | return 0; | ||
82 | |||
83 | return 1; | ||
84 | } |
libmailutils/string/strcount.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <limits.h> | ||
19 | #include <mailutils/util.h> | ||
20 | |||
21 | /* Return the number of occurrences of the ASCII character CHR in the | ||
22 | UTF-8 string STR. */ | ||
23 | size_t | ||
24 | mu_str_count (char const *str, int chr) | ||
25 | { | ||
26 | unsigned char c; | ||
27 | size_t count = 0; | ||
28 | int consume = 0; | ||
29 | |||
30 | if (!str || chr < 0 || chr > UCHAR_MAX) | ||
31 | return 0; | ||
32 | |||
33 | while ((c = *str++) != 0) | ||
34 | { | ||
35 | if (consume) | ||
36 | consume--; | ||
37 | else if (c < 0xc0) | ||
38 | { | ||
39 | if (c == chr) | ||
40 | count++; | ||
41 | } | ||
42 | else if (c & 0xc0) | ||
43 | consume = 1; | ||
44 | else if (c & 0xe0) | ||
45 | consume = 2; | ||
46 | else if (c & 0xf0) | ||
47 | consume = 3; | ||
48 | } | ||
49 | return count; | ||
50 | } |
... | @@ -436,7 +436,15 @@ main (int argc, char **argv) | ... | @@ -436,7 +436,15 @@ main (int argc, char **argv) |
436 | if (build_only || wh_env.nowhatnowproc) | 436 | if (build_only || wh_env.nowhatnowproc) |
437 | { | 437 | { |
438 | if (strcmp (wh_env.file, wh_env.draftfile)) | 438 | if (strcmp (wh_env.file, wh_env.draftfile)) |
439 | rename (wh_env.file, wh_env.draftfile); | 439 | { |
440 | rc = mu_rename_file (wh_env.file, wh_env.draftfile, MU_COPY_OVERWRITE); | ||
441 | if (rc) | ||
442 | { | ||
443 | mu_error (_("can't rename %s to %s: %s"), | ||
444 | wh_env.file, wh_env.draftfile, mu_strerror (rc)); | ||
445 | return 1; | ||
446 | } | ||
447 | } | ||
440 | return 0; | 448 | return 0; |
441 | } | 449 | } |
442 | 450 | ... | ... |
... | @@ -425,7 +425,13 @@ quit (struct mh_whatnow_env *wh, int argc, char **argv, int *status) | ... | @@ -425,7 +425,13 @@ quit (struct mh_whatnow_env *wh, int argc, char **argv, int *status) |
425 | { | 425 | { |
426 | mu_printf (_("draft left on \"%s\"."), wh->draftfile); | 426 | mu_printf (_("draft left on \"%s\"."), wh->draftfile); |
427 | if (strcmp (wh->file, wh->draftfile)) | 427 | if (strcmp (wh->file, wh->draftfile)) |
428 | rename (wh->file, wh->draftfile); | 428 | { |
429 | int rc; | ||
430 | rc = mu_rename_file (wh->file, wh->draftfile, MU_COPY_OVERWRITE); | ||
431 | if (rc) | ||
432 | mu_error (_("can't rename %s to %s: %s"), | ||
433 | wh->file, wh->draftfile, mu_strerror (rc)); | ||
434 | } | ||
429 | } | 435 | } |
430 | } | 436 | } |
431 | mu_printf ("\n"); | 437 | mu_printf ("\n"); | ... | ... |
... | @@ -1204,7 +1204,7 @@ list_iterator (size_t num, mu_message_t msg, void *data) | ... | @@ -1204,7 +1204,7 @@ list_iterator (size_t num, mu_message_t msg, void *data) |
1204 | } | 1204 | } |
1205 | 1205 | ||
1206 | int | 1206 | int |
1207 | mhn_list () | 1207 | mhn_list (void) |
1208 | { | 1208 | { |
1209 | int rc; | 1209 | int rc; |
1210 | 1210 | ||
... | @@ -1329,7 +1329,7 @@ sigint (int sig) | ... | @@ -1329,7 +1329,7 @@ sigint (int sig) |
1329 | } | 1329 | } |
1330 | 1330 | ||
1331 | static int | 1331 | static int |
1332 | mhn_pause () | 1332 | mhn_pause (void) |
1333 | { | 1333 | { |
1334 | char c; | 1334 | char c; |
1335 | int rc = 0; | 1335 | int rc = 0; |
... | @@ -1438,7 +1438,7 @@ show_iterator (size_t num, mu_message_t msg, void *data) | ... | @@ -1438,7 +1438,7 @@ show_iterator (size_t num, mu_message_t msg, void *data) |
1438 | } | 1438 | } |
1439 | 1439 | ||
1440 | int | 1440 | int |
1441 | mhn_show () | 1441 | mhn_show (void) |
1442 | { | 1442 | { |
1443 | 1443 | ||
1444 | int rc; | 1444 | int rc; |
... | @@ -1680,7 +1680,7 @@ store_iterator (size_t num, mu_message_t msg, void *data) | ... | @@ -1680,7 +1680,7 @@ store_iterator (size_t num, mu_message_t msg, void *data) |
1680 | } | 1680 | } |
1681 | 1681 | ||
1682 | int | 1682 | int |
1683 | mhn_store () | 1683 | mhn_store (void) |
1684 | { | 1684 | { |
1685 | int rc = 0; | 1685 | int rc = 0; |
1686 | 1686 | ||
... | @@ -2697,7 +2697,7 @@ mhn_header (mu_message_t msg, mu_message_t omsg) | ... | @@ -2697,7 +2697,7 @@ mhn_header (mu_message_t msg, mu_message_t omsg) |
2697 | } | 2697 | } |
2698 | 2698 | ||
2699 | int | 2699 | int |
2700 | mhn_compose () | 2700 | mhn_compose (void) |
2701 | { | 2701 | { |
2702 | int rc; | 2702 | int rc; |
2703 | mu_mime_t mime = NULL; | 2703 | mu_mime_t mime = NULL; |
... | @@ -2760,12 +2760,22 @@ mhn_compose () | ... | @@ -2760,12 +2760,22 @@ mhn_compose () |
2760 | 2760 | ||
2761 | /* Preserve the backup copy and replace the draft */ | 2761 | /* Preserve the backup copy and replace the draft */ |
2762 | unlink (backup); | 2762 | unlink (backup); |
2763 | rename (input_file, backup); | 2763 | |
2764 | rename (name, input_file); | 2764 | rc = mu_rename_file (input_file, backup, MU_COPY_OVERWRITE); |
2765 | if (rc) | ||
2766 | mu_error (_("can't rename %s to backup file %s: %s"), | ||
2767 | input_file, backup, mu_strerror (rc)); | ||
2768 | else | ||
2769 | { | ||
2770 | rc = mu_rename_file (name, input_file, 0); | ||
2771 | if (rc) | ||
2772 | mu_error (_("can't rename %s to %s: %s"), | ||
2773 | name, input_file, mu_strerror (rc)); | ||
2774 | } | ||
2765 | 2775 | ||
2766 | free (name); | 2776 | free (name); |
2767 | mu_mime_unref (mime); | 2777 | mu_mime_unref (mime); |
2768 | return 0; | 2778 | return rc; |
2769 | } | 2779 | } |
2770 | 2780 | ||
2771 | 2781 | ... | ... |
... | @@ -562,9 +562,13 @@ backup_file (const char *file_name) | ... | @@ -562,9 +562,13 @@ backup_file (const char *file_name) |
562 | 562 | ||
563 | if (unlink (new_name) && errno != ENOENT) | 563 | if (unlink (new_name) && errno != ENOENT) |
564 | mu_diag_funcall (MU_DIAG_ERROR, "unlink", new_name, errno); | 564 | mu_diag_funcall (MU_DIAG_ERROR, "unlink", new_name, errno); |
565 | else if (rename (file_name, new_name)) | 565 | else |
566 | mu_error (_("cannot rename `%s' to `%s': %s"), | 566 | { |
567 | file_name, new_name, mu_strerror (errno)); | 567 | int rc = mu_rename_file (file_name, new_name, MU_COPY_OVERWRITE); |
568 | if (rc) | ||
569 | mu_error (_("cannot rename %s to %s: %s"), | ||
570 | file_name, new_name, mu_strerror (errno)); | ||
571 | } | ||
568 | free (new_name); | 572 | free (new_name); |
569 | } | 573 | } |
570 | 574 | ... | ... |
-
Please register or sign in to post a comment