Mercurial > dovecot > core-2.2
annotate src/lib/unlink-directory.c @ 23007:36e01285b5b8
lib: buffer - Improve header comment for buffer_insert() and buffer_delete().
author | Stephan Bosch <stephan.bosch@dovecot.fi> |
---|---|
date | Mon, 18 Mar 2019 00:52:37 +0100 |
parents | cb108f786fb4 |
children |
rev | line source |
---|---|
22713
cb108f786fb4
Updated copyright notices to include the year 2018.
Stephan Bosch <stephan.bosch@dovecot.fi>
parents:
21390
diff
changeset
|
1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ |
1741
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
2 |
0 | 3 /* |
1741
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
4 There's a bit tricky race condition with recursive deletion. |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
5 Suppose this happens: |
0 | 6 |
1741
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
7 lstat(dir, ..) -> OK, it's a directory |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
8 // attacker deletes dir, replaces it with symlink to / |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
9 opendir(dir) -> it actually opens / |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
10 |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
11 Most portable solution is to lstat() the dir, chdir() there, then check |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
12 that "." points to same device/inode as we originally lstat()ed. This |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
13 assumes that the device has usable inodes, most should except for some NFS |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
14 implementations. |
0 | 15 |
1741
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
16 Filesystems may also reassign a deleted inode to another file |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
17 immediately after it's deleted. That in theory makes it possible to exploit |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
18 this race to delete the new directory. However, the new inode is quite |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
19 unlikely to be any important directory, and attacker is quite unlikely to |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
20 find out which directory even got the inode. Maybe with some setuid program |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
21 or daemon interaction something could come out of it though. |
0 | 22 |
1741
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
23 Another less portable solution is to fchdir(open(dir, O_NOFOLLOW)). |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
24 This should be completely safe. |
0 | 25 |
1741
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
26 The actual file deletion also has to be done relative to current |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
27 directory, to make sure that the whole directory structure isn't replaced |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
28 with another one while we're deleting it. Going back to parent directory |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
29 isn't too easy either - safest (and easiest) way again is to open() the |
9df02b1533b3
Removed most of the license comments from src/lib/*.c. It's just fine to
Timo Sirainen <tss@iki.fi>
parents:
1453
diff
changeset
|
30 directory and fchdir() back there. |
0 | 31 */ |
32 | |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
33 #define _GNU_SOURCE /* for O_NOFOLLOW with Linux */ |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
34 |
0 | 35 #include "lib.h" |
36 #include "unlink-directory.h" | |
37 | |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
38 #include <fcntl.h> |
0 | 39 #include <unistd.h> |
40 #include <dirent.h> | |
41 #include <sys/stat.h> | |
42 | |
15191
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
43 static int |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
44 unlink_directory_r(const char *dir, enum unlink_directory_flags flags) |
0 | 45 { |
46 DIR *dirp; | |
47 struct dirent *d; | |
48 struct stat st; | |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
49 int dir_fd, old_errno; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
50 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
51 #ifdef O_NOFOLLOW |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
52 dir_fd = open(dir, O_RDONLY | O_NOFOLLOW); |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
53 if (dir_fd == -1) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
54 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
55 #else |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
56 struct stat st2; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
57 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
58 if (lstat(dir, &st) < 0) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
59 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
60 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
61 if (!S_ISDIR(st.st_mode)) { |
12571
c67f4a2a2253
unlink_directory(): Return ELOOP for unexpected symlinks also when O_NOFOLLOW isn't supported.
Timo Sirainen <tss@iki.fi>
parents:
11984
diff
changeset
|
62 if ((st.st_mode & S_IFMT) != S_IFLNK) |
c67f4a2a2253
unlink_directory(): Return ELOOP for unexpected symlinks also when O_NOFOLLOW isn't supported.
Timo Sirainen <tss@iki.fi>
parents:
11984
diff
changeset
|
63 errno = ENOTDIR; |
c67f4a2a2253
unlink_directory(): Return ELOOP for unexpected symlinks also when O_NOFOLLOW isn't supported.
Timo Sirainen <tss@iki.fi>
parents:
11984
diff
changeset
|
64 else { |
c67f4a2a2253
unlink_directory(): Return ELOOP for unexpected symlinks also when O_NOFOLLOW isn't supported.
Timo Sirainen <tss@iki.fi>
parents:
11984
diff
changeset
|
65 /* be compatible with O_NOFOLLOW */ |
c67f4a2a2253
unlink_directory(): Return ELOOP for unexpected symlinks also when O_NOFOLLOW isn't supported.
Timo Sirainen <tss@iki.fi>
parents:
11984
diff
changeset
|
66 errno = ELOOP; |
c67f4a2a2253
unlink_directory(): Return ELOOP for unexpected symlinks also when O_NOFOLLOW isn't supported.
Timo Sirainen <tss@iki.fi>
parents:
11984
diff
changeset
|
67 } |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
68 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
69 } |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
70 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
71 dir_fd = open(dir, O_RDONLY); |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
72 if (dir_fd == -1) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
73 return -1; |
0 | 74 |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
75 if (fstat(dir_fd, &st2) < 0) { |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
76 i_close_fd(&dir_fd); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
77 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
78 } |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
79 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
80 if (st.st_ino != st2.st_ino || |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
81 !CMP_DEV_T(st.st_dev, st2.st_dev)) { |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
82 /* directory was just replaced with something else. */ |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
83 i_close_fd(&dir_fd); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
84 errno = ENOTDIR; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
85 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
86 } |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
87 #endif |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
88 if (fchdir(dir_fd) < 0) { |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
89 i_close_fd(&dir_fd); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
90 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
91 } |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
92 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
93 dirp = opendir("."); |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
94 if (dirp == NULL) { |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
95 i_close_fd(&dir_fd); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
96 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
97 } |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
98 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
99 errno = 0; |
0 | 100 while ((d = readdir(dirp)) != NULL) { |
15191
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
101 if (d->d_name[0] == '.') { |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
102 if ((d->d_name[1] == '\0' || |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
103 (d->d_name[1] == '.' && d->d_name[2] == '\0'))) { |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
104 /* skip . and .. */ |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
105 continue; |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
106 } |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
107 if ((flags & UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES) != 0) |
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
108 continue; |
0 | 109 } |
110 | |
1453 | 111 if (unlink(d->d_name) < 0 && errno != ENOENT) { |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
112 old_errno = errno; |
805
5ac361acb316
Marked all non-trivial buffer modifications with @UNSAFE tag. Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
113 |
1453 | 114 if (lstat(d->d_name, &st) < 0) { |
115 if (errno != ENOENT) | |
116 break; | |
117 errno = 0; | |
15403
a39024316d8e
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_FILES_ONLY
Timo Sirainen <tss@iki.fi>
parents:
15191
diff
changeset
|
118 } else if (S_ISDIR(st.st_mode) && |
a39024316d8e
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_FILES_ONLY
Timo Sirainen <tss@iki.fi>
parents:
15191
diff
changeset
|
119 (flags & UNLINK_DIRECTORY_FLAG_FILES_ONLY) == 0) { |
15191
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
120 if (unlink_directory_r(d->d_name, flags) < 0) { |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
121 if (errno != ENOENT) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
122 break; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
123 errno = 0; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
124 } |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
125 if (fchdir(dir_fd) < 0) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
126 break; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
127 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
128 if (rmdir(d->d_name) < 0) { |
11800
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
129 if (errno != ENOENT) { |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
130 if (errno == EEXIST) { |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
131 /* standardize errno */ |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
132 errno = ENOTEMPTY; |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
133 } |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
134 break; |
11800
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
135 } |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
136 errno = 0; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
137 } |
15403
a39024316d8e
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_FILES_ONLY
Timo Sirainen <tss@iki.fi>
parents:
15191
diff
changeset
|
138 } else if (S_ISDIR(st.st_mode) && |
a39024316d8e
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_FILES_ONLY
Timo Sirainen <tss@iki.fi>
parents:
15191
diff
changeset
|
139 (flags & UNLINK_DIRECTORY_FLAG_FILES_ONLY) != 0) { |
a39024316d8e
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_FILES_ONLY
Timo Sirainen <tss@iki.fi>
parents:
15191
diff
changeset
|
140 /* skip directory */ |
11984
2aec6c74902c
unlink_directory(): Don't log EBUSY error for unlink(.nfs*) directly.
Timo Sirainen <tss@iki.fi>
parents:
11800
diff
changeset
|
141 } else if (old_errno == EBUSY && |
2aec6c74902c
unlink_directory(): Don't log EBUSY error for unlink(.nfs*) directly.
Timo Sirainen <tss@iki.fi>
parents:
11800
diff
changeset
|
142 strncmp(d->d_name, ".nfs", 4) == 0) { |
2aec6c74902c
unlink_directory(): Don't log EBUSY error for unlink(.nfs*) directly.
Timo Sirainen <tss@iki.fi>
parents:
11800
diff
changeset
|
143 /* can't delete NFS files that are still |
2aec6c74902c
unlink_directory(): Don't log EBUSY error for unlink(.nfs*) directly.
Timo Sirainen <tss@iki.fi>
parents:
11800
diff
changeset
|
144 in use. let the caller decide if this error |
2aec6c74902c
unlink_directory(): Don't log EBUSY error for unlink(.nfs*) directly.
Timo Sirainen <tss@iki.fi>
parents:
11800
diff
changeset
|
145 is worth logging about */ |
2aec6c74902c
unlink_directory(): Don't log EBUSY error for unlink(.nfs*) directly.
Timo Sirainen <tss@iki.fi>
parents:
11800
diff
changeset
|
146 break; |
0 | 147 } else { |
1453 | 148 /* so it wasn't a directory */ |
805
5ac361acb316
Marked all non-trivial buffer modifications with @UNSAFE tag. Several
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
149 errno = old_errno; |
9917
81011be1092f
unlink_directory(): Log if unlink()ing some file fails.
Timo Sirainen <tss@iki.fi>
parents:
8590
diff
changeset
|
150 i_error("unlink(%s/%s) failed: %m", |
81011be1092f
unlink_directory(): Log if unlink()ing some file fails.
Timo Sirainen <tss@iki.fi>
parents:
8590
diff
changeset
|
151 dir, d->d_name); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
152 break; |
0 | 153 } |
154 } | |
155 } | |
1452
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
156 old_errno = errno; |
0 | 157 |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
158 i_close_fd(&dir_fd); |
822
5101f8bf2368
If used base/login directories exist already, make sure they're with correct
Timo Sirainen <tss@iki.fi>
parents:
817
diff
changeset
|
159 if (closedir(dirp) < 0) |
5101f8bf2368
If used base/login directories exist already, make sure they're with correct
Timo Sirainen <tss@iki.fi>
parents:
817
diff
changeset
|
160 return -1; |
0 | 161 |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
162 if (old_errno != 0) { |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
163 errno = old_errno; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
164 return -1; |
822
5101f8bf2368
If used base/login directories exist already, make sure they're with correct
Timo Sirainen <tss@iki.fi>
parents:
817
diff
changeset
|
165 } |
5101f8bf2368
If used base/login directories exist already, make sure they're with correct
Timo Sirainen <tss@iki.fi>
parents:
817
diff
changeset
|
166 |
5101f8bf2368
If used base/login directories exist already, make sure they're with correct
Timo Sirainen <tss@iki.fi>
parents:
817
diff
changeset
|
167 return 0; |
0 | 168 } |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
169 |
15191
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
170 int unlink_directory(const char *dir, enum unlink_directory_flags flags) |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
171 { |
1452
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
172 int fd, ret, old_errno; |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
173 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
174 fd = open(".", O_RDONLY); |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
175 if (fd == -1) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
176 return -1; |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
177 |
15191
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
178 ret = unlink_directory_r(dir, flags); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
179 if (ret < 0 && errno == ENOENT) |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
180 ret = 0; |
1452
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
181 old_errno = errno; |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
182 |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
183 if (fchdir(fd) < 0) { |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
184 i_fatal("unlink_directory(%s): " |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
185 "Can't fchdir() back to our original dir: %m", dir); |
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
186 } |
14691
3945a3646c67
Changed i_close_fd() API to set the fd to -1 after closing.
Timo Sirainen <tss@iki.fi>
parents:
14687
diff
changeset
|
187 i_close_fd(&fd); |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
188 |
1452
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
189 if (ret < 0) { |
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
190 errno = old_errno; |
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
191 return -1; |
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
192 } |
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
193 |
15191
b9cb9c3cdfdc
unlink_directory(): Added UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES flag.
Timo Sirainen <tss@iki.fi>
parents:
14691
diff
changeset
|
194 if ((flags & UNLINK_DIRECTORY_FLAG_RMDIR) != 0) { |
11800
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
195 if (rmdir(dir) < 0 && errno != ENOENT) { |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
196 if (errno == EEXIST) { |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
197 /* standardize errno */ |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
198 errno = ENOTEMPTY; |
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
199 } |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
200 return -1; |
11800
6ebe8d8fd1fd
Handle rmdir() failing with EEXIST the same as failing with ENOTEMPTY.
Timo Sirainen <tss@iki.fi>
parents:
10582
diff
changeset
|
201 } |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
202 } |
1452
22495f001acc
Returned errno was often wrong.
Timo Sirainen <tss@iki.fi>
parents:
1249
diff
changeset
|
203 return 0; |
1243
478471737964
unlink_directory() is now (hopefully) race-condition free.
Timo Sirainen <tss@iki.fi>
parents:
822
diff
changeset
|
204 } |