Mercurial > hg > nginx
annotate src/core/ngx_open_file_cache.c @ 5356:acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
It was introduced in Linux 2.6.39, glibc 2.14 and allows to obtain
file descriptors without actually opening files. Thus made it possible
to traverse path with openat() syscalls without the need to have read
permissions for path components. It is effectively emulates O_SEARCH
which is missing on Linux.
O_PATH is used in combination with O_RDONLY. The last one is ignored
if O_PATH is used, but it allows nginx to not fail when it was built on
modern system (i.e. glibc 2.14+) and run with a kernel older than 2.6.39.
Then O_PATH is unknown to the kernel and ignored, while O_RDONLY is used.
Sadly, fstat() is not working with O_PATH descriptors till Linux 3.6.
As a workaround we fallback to fstatat() with the AT_EMPTY_PATH flag
that was introduced at the same time as O_PATH.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Mon, 02 Sep 2013 08:07:59 +0400 |
parents | 6b479db5b52b |
children | 659464c695b7 |
rev | line source |
---|---|
1453 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
1453 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_event.h> | |
11 | |
12 | |
13 /* | |
14 * open file cache caches | |
15 * open file handles with stat() info; | |
16 * directories stat() info; | |
17 * files and directories errors: not found, access denied, etc. | |
18 */ | |
19 | |
20 | |
3178 | 21 #define NGX_MIN_READ_AHEAD (128 * 1024) |
22 | |
23 | |
1453 | 24 static void ngx_open_file_cache_cleanup(void *data); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
25 #if (NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
26 static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
27 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); |
5356
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
28 #if (NGX_HAVE_O_PATH) |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
29 static ngx_int_t ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
30 ngx_log_t *log); |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
31 #endif |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
32 #endif |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
33 static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
34 ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
35 ngx_int_t access, ngx_log_t *log); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
36 static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
37 ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
38 static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, |
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
39 ngx_open_file_info_t *of, ngx_log_t *log); |
1775 | 40 static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, |
41 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); | |
1453 | 42 static void ngx_open_file_cleanup(void *data); |
43 static void ngx_close_cached_file(ngx_open_file_cache_t *cache, | |
1772 | 44 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log); |
1775 | 45 static void ngx_open_file_del_event(ngx_cached_open_file_t *file); |
1453 | 46 static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, |
47 ngx_uint_t n, ngx_log_t *log); | |
48 static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | |
49 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | |
1775 | 50 static ngx_cached_open_file_t * |
51 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
52 uint32_t hash); | |
1453 | 53 static void ngx_open_file_cache_remove(ngx_event_t *ev); |
54 | |
55 | |
56 ngx_open_file_cache_t * | |
57 ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive) | |
58 { | |
59 ngx_pool_cleanup_t *cln; | |
60 ngx_open_file_cache_t *cache; | |
61 | |
62 cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t)); | |
63 if (cache == NULL) { | |
64 return NULL; | |
65 } | |
66 | |
1761 | 67 ngx_rbtree_init(&cache->rbtree, &cache->sentinel, |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1458
diff
changeset
|
68 ngx_open_file_cache_rbtree_insert_value); |
1453 | 69 |
1765 | 70 ngx_queue_init(&cache->expire_queue); |
71 | |
1453 | 72 cache->current = 0; |
73 cache->max = max; | |
74 cache->inactive = inactive; | |
75 | |
76 cln = ngx_pool_cleanup_add(pool, 0); | |
77 if (cln == NULL) { | |
78 return NULL; | |
79 } | |
80 | |
81 cln->handler = ngx_open_file_cache_cleanup; | |
82 cln->data = cache; | |
83 | |
84 return cache; | |
85 } | |
86 | |
87 | |
88 static void | |
89 ngx_open_file_cache_cleanup(void *data) | |
90 { | |
91 ngx_open_file_cache_t *cache = data; | |
92 | |
1765 | 93 ngx_queue_t *q; |
1453 | 94 ngx_cached_open_file_t *file; |
95 | |
96 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, | |
97 "open file cache cleanup"); | |
98 | |
99 for ( ;; ) { | |
100 | |
1765 | 101 if (ngx_queue_empty(&cache->expire_queue)) { |
1766 | 102 break; |
1453 | 103 } |
104 | |
1765 | 105 q = ngx_queue_last(&cache->expire_queue); |
106 | |
107 file = ngx_queue_data(q, ngx_cached_open_file_t, queue); | |
108 | |
109 ngx_queue_remove(q); | |
1453 | 110 |
111 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
112 | |
113 cache->current--; | |
114 | |
115 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, | |
116 "delete cached open file: %s", file->name); | |
117 | |
118 if (!file->err && !file->is_dir) { | |
119 file->close = 1; | |
120 file->count = 0; | |
1772 | 121 ngx_close_cached_file(cache, file, 0, ngx_cycle->log); |
1453 | 122 |
123 } else { | |
124 ngx_free(file->name); | |
125 ngx_free(file); | |
126 } | |
127 } | |
128 | |
129 if (cache->current) { | |
130 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
5327
6b479db5b52b
Format specifier fixes in error logging.
Sergey Kandaurov <pluknet@nginx.com>
parents:
4497
diff
changeset
|
131 "%ui items still leave in open file cache", |
1453 | 132 cache->current); |
133 } | |
134 | |
135 if (cache->rbtree.root != cache->rbtree.sentinel) { | |
136 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
137 "rbtree still is not empty in open file cache"); | |
138 | |
139 } | |
140 } | |
141 | |
142 | |
143 ngx_int_t | |
144 ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
145 ngx_open_file_info_t *of, ngx_pool_t *pool) | |
146 { | |
147 time_t now; | |
148 uint32_t hash; | |
149 ngx_int_t rc; | |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
150 ngx_file_info_t fi; |
1453 | 151 ngx_pool_cleanup_t *cln; |
152 ngx_cached_open_file_t *file; | |
153 ngx_pool_cleanup_file_t *clnf; | |
154 ngx_open_file_cache_cleanup_t *ofcln; | |
155 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
156 of->fd = NGX_INVALID_FILE; |
1453 | 157 of->err = 0; |
158 | |
159 if (cache == NULL) { | |
160 | |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
161 if (of->test_only) { |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
162 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
163 if (ngx_file_info_wrapper(name, of, &fi, pool->log) |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
164 == NGX_FILE_ERROR) |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
165 { |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
166 return NGX_ERROR; |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
167 } |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
168 |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
169 of->uniq = ngx_file_uniq(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
170 of->mtime = ngx_file_mtime(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
171 of->size = ngx_file_size(&fi); |
3899
e7cd13b7f759
Use more precise stat.st_blocks to account cache size on Unix
Igor Sysoev <igor@sysoev.ru>
parents:
3497
diff
changeset
|
172 of->fs_size = ngx_file_fs_size(&fi); |
2756
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
173 of->is_dir = ngx_is_dir(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
174 of->is_file = ngx_is_file(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
175 of->is_link = ngx_is_link(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
176 of->is_exec = ngx_is_exec(&fi); |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
177 |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
178 return NGX_OK; |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
179 } |
09cab3f8d92e
*) of.test_only to not open file if only stat() is enough
Igor Sysoev <igor@sysoev.ru>
parents:
2629
diff
changeset
|
180 |
1453 | 181 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); |
182 if (cln == NULL) { | |
183 return NGX_ERROR; | |
184 } | |
185 | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
186 rc = ngx_open_and_stat_file(name, of, pool->log); |
1453 | 187 |
188 if (rc == NGX_OK && !of->is_dir) { | |
189 cln->handler = ngx_pool_cleanup_file; | |
190 clnf = cln->data; | |
191 | |
192 clnf->fd = of->fd; | |
193 clnf->name = name->data; | |
194 clnf->log = pool->log; | |
195 } | |
196 | |
197 return rc; | |
198 } | |
199 | |
200 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); | |
201 if (cln == NULL) { | |
202 return NGX_ERROR; | |
203 } | |
204 | |
205 now = ngx_time(); | |
206 | |
1775 | 207 hash = ngx_crc32_long(name->data, name->len); |
208 | |
209 file = ngx_open_file_lookup(cache, name, hash); | |
210 | |
211 if (file) { | |
212 | |
213 file->uses++; | |
214 | |
1987 | 215 ngx_queue_remove(&file->queue); |
216 | |
1775 | 217 if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) { |
218 | |
219 /* file was not used often enough to keep open */ | |
220 | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
221 rc = ngx_open_and_stat_file(name, of, pool->log); |
1453 | 222 |
1775 | 223 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { |
224 goto failed; | |
225 } | |
226 | |
227 goto add_event; | |
1453 | 228 } |
229 | |
2070 | 230 if (file->use_event |
2063
67a29af877ed
initialize of.uniq in ngx_open_cached_file()
Igor Sysoev <igor@sysoev.ru>
parents:
2006
diff
changeset
|
231 || (file->event == NULL |
67a29af877ed
initialize of.uniq in ngx_open_cached_file()
Igor Sysoev <igor@sysoev.ru>
parents:
2006
diff
changeset
|
232 && (of->uniq == 0 || of->uniq == file->uniq) |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
233 && now - file->created < of->valid |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
234 #if (NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
235 && of->disable_symlinks == file->disable_symlinks |
4493
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
236 && of->disable_symlinks_from == file->disable_symlinks_from |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
237 #endif |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
238 )) |
1775 | 239 { |
240 if (file->err == 0) { | |
1772 | 241 |
1775 | 242 of->fd = file->fd; |
243 of->uniq = file->uniq; | |
244 of->mtime = file->mtime; | |
245 of->size = file->size; | |
1453 | 246 |
1775 | 247 of->is_dir = file->is_dir; |
248 of->is_file = file->is_file; | |
249 of->is_link = file->is_link; | |
250 of->is_exec = file->is_exec; | |
2246
987831d73bd8
cache directio flag in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2231
diff
changeset
|
251 of->is_directio = file->is_directio; |
1453 | 252 |
1775 | 253 if (!file->is_dir) { |
254 file->count++; | |
255 ngx_open_file_add_event(cache, file, of, pool->log); | |
1453 | 256 } |
257 | |
1775 | 258 } else { |
259 of->err = file->err; | |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
260 #if (NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
261 of->failed = file->disable_symlinks ? ngx_openat_file_n |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
262 : ngx_open_file_n; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
263 #else |
2783
87c088e6956a
set of.failed for cached error, the bug has been introduced in r2757
Igor Sysoev <igor@sysoev.ru>
parents:
2782
diff
changeset
|
264 of->failed = ngx_open_file_n; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
265 #endif |
1775 | 266 } |
267 | |
268 goto found; | |
269 } | |
270 | |
271 ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, | |
272 "retest open file: %s, fd:%d, c:%d, e:%d", | |
273 file->name, file->fd, file->count, file->err); | |
1453 | 274 |
1775 | 275 if (file->is_dir) { |
276 | |
277 /* | |
278 * chances that directory became file are very small | |
279 * so test_dir flag allows to use a single syscall | |
280 * in ngx_file_info() instead of three syscalls | |
281 */ | |
282 | |
283 of->test_dir = 1; | |
284 } | |
285 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
286 of->fd = file->fd; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
287 of->uniq = file->uniq; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
288 |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
289 rc = ngx_open_and_stat_file(name, of, pool->log); |
1453 | 290 |
1775 | 291 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { |
292 goto failed; | |
293 } | |
294 | |
295 if (of->is_dir) { | |
296 | |
297 if (file->is_dir || file->err) { | |
298 goto update; | |
299 } | |
300 | |
301 /* file became directory */ | |
1453 | 302 |
1775 | 303 } else if (of->err == 0) { /* file */ |
304 | |
305 if (file->is_dir || file->err) { | |
306 goto add_event; | |
307 } | |
1453 | 308 |
2070 | 309 if (of->uniq == file->uniq) { |
1453 | 310 |
1775 | 311 if (file->event) { |
312 file->use_event = 1; | |
1453 | 313 } |
314 | |
4101
31cf2902de60
Fix of the previous commit: is_directio flag processing introduced in r4077
Igor Sysoev <igor@sysoev.ru>
parents:
4100
diff
changeset
|
315 of->is_directio = file->is_directio; |
31cf2902de60
Fix of the previous commit: is_directio flag processing introduced in r4077
Igor Sysoev <igor@sysoev.ru>
parents:
4100
diff
changeset
|
316 |
4100
efeee901439a
Bugfix: open_file_cache did not update file info on retest.
Igor Sysoev <igor@sysoev.ru>
parents:
4076
diff
changeset
|
317 goto update; |
1775 | 318 } |
1453 | 319 |
1775 | 320 /* file was changed */ |
1453 | 321 |
1775 | 322 } else { /* error to cache */ |
1453 | 323 |
1775 | 324 if (file->err || file->is_dir) { |
325 goto update; | |
1453 | 326 } |
327 | |
1775 | 328 /* file was removed, etc. */ |
329 } | |
330 | |
331 if (file->count == 0) { | |
332 | |
333 ngx_open_file_del_event(file); | |
1453 | 334 |
1775 | 335 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { |
336 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
337 ngx_close_file_n " \"%V\" failed", name); |
1775 | 338 } |
1453 | 339 |
1775 | 340 goto add_event; |
341 } | |
342 | |
343 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
344 | |
345 cache->current--; | |
346 | |
347 file->close = 1; | |
348 | |
349 goto create; | |
1453 | 350 } |
351 | |
352 /* not found */ | |
353 | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
354 rc = ngx_open_and_stat_file(name, of, pool->log); |
1453 | 355 |
356 if (rc != NGX_OK && (of->err == 0 || !of->errors)) { | |
357 goto failed; | |
358 } | |
359 | |
360 create: | |
361 | |
362 if (cache->current >= cache->max) { | |
363 ngx_expire_old_cached_files(cache, 0, pool->log); | |
364 } | |
365 | |
366 file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log); | |
367 | |
368 if (file == NULL) { | |
369 goto failed; | |
370 } | |
371 | |
372 file->name = ngx_alloc(name->len + 1, pool->log); | |
373 | |
374 if (file->name == NULL) { | |
375 ngx_free(file); | |
376 file = NULL; | |
377 goto failed; | |
378 } | |
379 | |
380 ngx_cpystrn(file->name, name->data, name->len + 1); | |
381 | |
382 file->node.key = hash; | |
383 | |
384 ngx_rbtree_insert(&cache->rbtree, &file->node); | |
385 | |
386 cache->current++; | |
387 | |
1775 | 388 file->uses = 1; |
1453 | 389 file->count = 0; |
2934
b6d588fa3ee9
initialize use_event field in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2783
diff
changeset
|
390 file->use_event = 0; |
1775 | 391 file->event = NULL; |
392 | |
393 add_event: | |
394 | |
395 ngx_open_file_add_event(cache, file, of, pool->log); | |
1453 | 396 |
397 update: | |
398 | |
399 file->fd = of->fd; | |
400 file->err = of->err; | |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
401 #if (NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
402 file->disable_symlinks = of->disable_symlinks; |
4493
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
403 file->disable_symlinks_from = of->disable_symlinks_from; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
404 #endif |
1453 | 405 |
406 if (of->err == 0) { | |
407 file->uniq = of->uniq; | |
408 file->mtime = of->mtime; | |
409 file->size = of->size; | |
410 | |
411 file->close = 0; | |
412 | |
413 file->is_dir = of->is_dir; | |
414 file->is_file = of->is_file; | |
415 file->is_link = of->is_link; | |
416 file->is_exec = of->is_exec; | |
2246
987831d73bd8
cache directio flag in open file cache
Igor Sysoev <igor@sysoev.ru>
parents:
2231
diff
changeset
|
417 file->is_directio = of->is_directio; |
1453 | 418 |
419 if (!of->is_dir) { | |
420 file->count++; | |
421 } | |
422 } | |
423 | |
424 file->created = now; | |
425 | |
426 found: | |
427 | |
428 file->accessed = now; | |
429 | |
1765 | 430 ngx_queue_insert_head(&cache->expire_queue, &file->queue); |
1453 | 431 |
1772 | 432 ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, |
433 "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", | |
434 file->name, file->fd, file->count, file->err, file->uses); | |
1453 | 435 |
436 if (of->err == 0) { | |
437 | |
438 if (!of->is_dir) { | |
439 cln->handler = ngx_open_file_cleanup; | |
440 ofcln = cln->data; | |
441 | |
442 ofcln->cache = cache; | |
443 ofcln->file = file; | |
1772 | 444 ofcln->min_uses = of->min_uses; |
1453 | 445 ofcln->log = pool->log; |
446 } | |
447 | |
448 return NGX_OK; | |
449 } | |
450 | |
451 return NGX_ERROR; | |
452 | |
453 failed: | |
454 | |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
455 if (file) { |
1453 | 456 ngx_rbtree_delete(&cache->rbtree, &file->node); |
457 | |
458 cache->current--; | |
459 | |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
460 if (file->count == 0) { |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
461 |
2006
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
462 if (file->fd != NGX_INVALID_FILE) { |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
463 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
464 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
465 ngx_close_file_n " \"%s\" failed", |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
466 file->name); |
2006
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
467 } |
b52cb9bf2064
style fix: remove tabs and trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1988
diff
changeset
|
468 } |
1988
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
469 |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
470 ngx_free(file->name); |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
471 ngx_free(file); |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
472 |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
473 } else { |
34051c712e41
fix segfault when file is deleted and open_file_cache_errors is off
Igor Sysoev <igor@sysoev.ru>
parents:
1987
diff
changeset
|
474 file->close = 1; |
1453 | 475 } |
476 } | |
477 | |
478 if (of->fd != NGX_INVALID_FILE) { | |
479 if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { | |
480 ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
481 ngx_close_file_n " \"%V\" failed", name); |
1453 | 482 } |
483 } | |
484 | |
485 return NGX_ERROR; | |
486 } | |
487 | |
488 | |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
489 #if (NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
490 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
491 static ngx_fd_t |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
492 ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
493 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
494 { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
495 ngx_fd_t fd; |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
496 ngx_err_t err; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
497 ngx_file_info_t fi, atfi; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
498 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
499 /* |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
500 * To allow symlinks with the same owner, use openat() (followed |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
501 * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
502 * uids between fstat() and fstatat(). |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
503 * |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
504 * As there is a race between openat() and fstatat() we don't |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
505 * know if openat() in fact opened symlink or not. Therefore, |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
506 * we have to compare uids even if fstatat() reports the opened |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
507 * component isn't a symlink (as we don't know whether it was |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
508 * symlink during openat() or not). |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
509 */ |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
510 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
511 fd = ngx_openat_file(at_fd, name, mode, create, access); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
512 |
4486
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
513 if (fd == NGX_INVALID_FILE) { |
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
514 return NGX_INVALID_FILE; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
515 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
516 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
517 if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
518 == NGX_FILE_ERROR) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
519 { |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
520 err = ngx_errno; |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
521 goto failed; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
522 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
523 |
5356
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
524 #if (NGX_HAVE_O_PATH) |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
525 if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) { |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
526 err = ngx_errno; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
527 goto failed; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
528 } |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
529 #else |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
530 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
531 err = ngx_errno; |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
532 goto failed; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
533 } |
5356
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
534 #endif |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
535 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
536 if (fi.st_uid != atfi.st_uid) { |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
537 err = NGX_ELOOP; |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
538 goto failed; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
539 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
540 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
541 return fd; |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
542 |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
543 failed: |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
544 |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
545 if (ngx_close_file(fd) == NGX_FILE_ERROR) { |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
546 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
547 ngx_close_file_n " \"%V\" failed", name); |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
548 } |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
549 |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
550 ngx_set_errno(err); |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
551 |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
552 return NGX_INVALID_FILE; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
553 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
554 |
5356
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
555 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
556 #if (NGX_HAVE_O_PATH) |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
557 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
558 static ngx_int_t |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
559 ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log) |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
560 { |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
561 static ngx_uint_t use_fstat = 1; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
562 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
563 /* |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
564 * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
565 * a descriptor without actually opening file or directory. It requires |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
566 * less permissions for path components, but till Linux 3.6 fstat() returns |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
567 * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
568 * should be used instead. |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
569 * |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
570 * Three scenarios are handled in this function: |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
571 * |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
572 * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
573 * backported by vendor. Then fstat() is used. |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
574 * |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
575 * 2) The kernel is newer than 2.6.39 but older than 3.6. In this case |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
576 * the first call of fstat() returns EBADF and we fallback to fstatat() |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
577 * with AT_EMPTY_PATH which was introduced at the same time as O_PATH. |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
578 * |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
579 * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
580 * support. Since descriptors are opened with O_PATH|O_RDONLY flags |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
581 * and O_PATH is ignored by the kernel then the O_RDONLY flag is |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
582 * actually used. In this case fstat() just works. |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
583 */ |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
584 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
585 if (use_fstat) { |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
586 if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) { |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
587 return NGX_OK; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
588 } |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
589 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
590 if (ngx_errno != NGX_EBADF) { |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
591 return NGX_ERROR; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
592 } |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
593 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
594 ngx_log_error(NGX_LOG_NOTICE, log, 0, |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
595 "fstat(O_PATH) failed with EBADF, " |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
596 "switching to fstatat(AT_EMPTY_PATH)"); |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
597 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
598 use_fstat = 0; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
599 return ngx_file_o_path_info(fd, fi, log); |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
600 } |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
601 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
602 if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) { |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
603 return NGX_OK; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
604 } |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
605 |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
606 return NGX_ERROR; |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
607 } |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
608 |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
609 #endif |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
610 |
5356
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
611 #endif /* NGX_HAVE_OPENAT */ |
acd51b0f6fd4
Disable symlinks: use O_PATH to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
5327
diff
changeset
|
612 |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
613 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
614 static ngx_fd_t |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
615 ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
616 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
617 { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
618 ngx_fd_t fd; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
619 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
620 #if !(NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
621 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
622 fd = ngx_open_file(name->data, mode, create, access); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
623 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
624 if (fd == NGX_INVALID_FILE) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
625 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
626 of->failed = ngx_open_file_n; |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
627 return NGX_INVALID_FILE; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
628 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
629 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
630 return fd; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
631 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
632 #else |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
633 |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
634 u_char *p, *cp, *end; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
635 ngx_fd_t at_fd; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
636 ngx_str_t at_name; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
637 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
638 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
639 fd = ngx_open_file(name->data, mode, create, access); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
640 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
641 if (fd == NGX_INVALID_FILE) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
642 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
643 of->failed = ngx_open_file_n; |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
644 return NGX_INVALID_FILE; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
645 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
646 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
647 return fd; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
648 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
649 |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
650 p = name->data; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
651 end = p + name->len; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
652 |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
653 at_name = *name; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
654 |
4493
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
655 if (of->disable_symlinks_from) { |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
656 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
657 cp = p + of->disable_symlinks_from; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
658 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
659 *cp = '\0'; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
660 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
661 at_fd = ngx_open_file(p, NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
662 NGX_FILE_OPEN, 0); |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
663 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
664 *cp = '/'; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
665 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
666 if (at_fd == NGX_INVALID_FILE) { |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
667 of->err = ngx_errno; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
668 of->failed = ngx_open_file_n; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
669 return NGX_INVALID_FILE; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
670 } |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
671 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
672 at_name.len = of->disable_symlinks_from; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
673 p = cp + 1; |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
674 |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
675 } else if (*p == '/') { |
47ece8818978
Disable symlinks: added the "from" parameter support to the open file cache.
Valentin Bartenev <vbart@nginx.com>
parents:
4488
diff
changeset
|
676 |
4486
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
677 at_fd = ngx_open_file("/", |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
678 NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, |
4486
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
679 NGX_FILE_OPEN, 0); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
680 |
4484
f78a29a2f9e6
Disable symlinks: error handling cleanup again.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4480
diff
changeset
|
681 if (at_fd == NGX_INVALID_FILE) { |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
682 of->err = ngx_errno; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
683 of->failed = ngx_openat_file_n; |
4484
f78a29a2f9e6
Disable symlinks: error handling cleanup again.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4480
diff
changeset
|
684 return NGX_INVALID_FILE; |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
685 } |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
686 |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
687 at_name.len = 1; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
688 p++; |
4486
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
689 |
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
690 } else { |
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
691 at_fd = NGX_AT_FDCWD; |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
692 } |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
693 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
694 for ( ;; ) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
695 cp = ngx_strlchr(p, end, '/'); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
696 if (cp == NULL) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
697 break; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
698 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
699 |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
700 if (cp == p) { |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
701 p++; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
702 continue; |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
703 } |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
704 |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
705 *cp = '\0'; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
706 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
707 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
708 fd = ngx_openat_file_owner(at_fd, p, |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
709 NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
710 NGX_FILE_OPEN, 0, log); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
711 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
712 } else { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
713 fd = ngx_openat_file(at_fd, p, |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
714 NGX_FILE_SEARCH|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW, |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
715 NGX_FILE_OPEN, 0); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
716 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
717 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
718 *cp = '/'; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
719 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
720 if (fd == NGX_INVALID_FILE) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
721 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
722 of->failed = ngx_openat_file_n; |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
723 goto failed; |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
724 } |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
725 |
4485
f7d131008e9c
Disable symlinks: added explicit cast of AT_FDCWD (ticket #111).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4484
diff
changeset
|
726 if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
727 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
4484
f78a29a2f9e6
Disable symlinks: error handling cleanup again.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4480
diff
changeset
|
728 ngx_close_file_n " \"%V\" failed", &at_name); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
729 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
730 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
731 p = cp + 1; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
732 at_fd = fd; |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
733 at_name.len = cp - at_name.data; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
734 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
735 |
4486
a996bb40a0bb
Disable symlinks: cleanups once again.
Valentin Bartenev <vbart@nginx.com>
parents:
4485
diff
changeset
|
736 if (p == end) { |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
737 |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
738 /* |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
739 * If pathname ends with a trailing slash, assume the last path |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
740 * component is a directory and reopen it with requested flags; |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
741 * if not, fail with ENOTDIR as per POSIX. |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
742 * |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
743 * We cannot rely on O_DIRECTORY in the loop above to check |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
744 * that the last path component is a directory because |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
745 * O_DIRECTORY doesn't work on FreeBSD 8. Fortunately, by |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
746 * reopening a directory, we don't depend on it at all. |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
747 */ |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
748 |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
749 fd = ngx_openat_file(at_fd, ".", mode, create, access); |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
750 goto done; |
4480
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
751 } |
5a3cb84545e5
Disable symlinks: fixed edge cases of path handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4479
diff
changeset
|
752 |
4487
a786c85e8268
Disable symlinks: don't allow creating or truncating a file via a symlink in
Valentin Bartenev <vbart@nginx.com>
parents:
4486
diff
changeset
|
753 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER |
a786c85e8268
Disable symlinks: don't allow creating or truncating a file via a symlink in
Valentin Bartenev <vbart@nginx.com>
parents:
4486
diff
changeset
|
754 && !(create & (NGX_FILE_CREATE_OR_OPEN|NGX_FILE_TRUNCATE))) |
a786c85e8268
Disable symlinks: don't allow creating or truncating a file via a symlink in
Valentin Bartenev <vbart@nginx.com>
parents:
4486
diff
changeset
|
755 { |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
756 fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
757 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
758 } else { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
759 fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
760 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
761 |
4488
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
762 done: |
d33ce8cd0d70
Disable symlinks: use O_SEARCH|O_DIRECTORY to open path components.
Valentin Bartenev <vbart@nginx.com>
parents:
4487
diff
changeset
|
763 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
764 if (fd == NGX_INVALID_FILE) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
765 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
766 of->failed = ngx_openat_file_n; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
767 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
768 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
769 failed: |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
770 |
4485
f7d131008e9c
Disable symlinks: added explicit cast of AT_FDCWD (ticket #111).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4484
diff
changeset
|
771 if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
772 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
4484
f78a29a2f9e6
Disable symlinks: error handling cleanup again.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4480
diff
changeset
|
773 ngx_close_file_n " \"%V\" failed", &at_name); |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
774 } |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
775 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
776 return fd; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
777 #endif |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
778 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
779 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
780 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
781 static ngx_int_t |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
782 ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
783 ngx_file_info_t *fi, ngx_log_t *log) |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
784 { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
785 ngx_int_t rc; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
786 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
787 #if !(NGX_HAVE_OPENAT) |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
788 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
789 rc = ngx_file_info(name->data, fi); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
790 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
791 if (rc == NGX_FILE_ERROR) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
792 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
793 of->failed = ngx_file_info_n; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
794 return NGX_FILE_ERROR; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
795 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
796 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
797 return rc; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
798 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
799 #else |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
800 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
801 ngx_fd_t fd; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
802 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
803 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
804 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
805 rc = ngx_file_info(name->data, fi); |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
806 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
807 if (rc == NGX_FILE_ERROR) { |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
808 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
809 of->failed = ngx_file_info_n; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
810 return NGX_FILE_ERROR; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
811 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
812 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
813 return rc; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
814 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
815 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
816 fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
817 NGX_FILE_OPEN, 0, log); |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
818 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
819 if (fd == NGX_INVALID_FILE) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
820 return NGX_FILE_ERROR; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
821 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
822 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
823 rc = ngx_fd_info(fd, fi); |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
824 |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
825 if (rc == NGX_FILE_ERROR) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
826 of->err = ngx_errno; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
827 of->failed = ngx_fd_info_n; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
828 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
829 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
830 if (ngx_close_file(fd) == NGX_FILE_ERROR) { |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
831 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
832 ngx_close_file_n " \"%V\" failed", name); |
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
833 } |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
834 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
835 return rc; |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
836 #endif |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
837 } |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
838 |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
839 |
1453 | 840 static ngx_int_t |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
841 ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, |
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
842 ngx_log_t *log) |
1453 | 843 { |
844 ngx_fd_t fd; | |
845 ngx_file_info_t fi; | |
846 | |
2070 | 847 if (of->fd != NGX_INVALID_FILE) { |
1453 | 848 |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
849 if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
850 of->fd = NGX_INVALID_FILE; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
851 return NGX_ERROR; |
1453 | 852 } |
853 | |
2070 | 854 if (of->uniq == ngx_file_uniq(&fi)) { |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
855 goto done; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
856 } |
1453 | 857 |
2070 | 858 } else if (of->test_dir) { |
859 | |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
860 if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
861 of->fd = NGX_INVALID_FILE; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
862 return NGX_ERROR; |
2070 | 863 } |
864 | |
2460
225fa4abd76f
test ngx_file_info() result, the bug has been introduced in r2070
Igor Sysoev <igor@sysoev.ru>
parents:
2246
diff
changeset
|
865 if (ngx_is_dir(&fi)) { |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
866 goto done; |
1453 | 867 } |
868 } | |
869 | |
2072 | 870 if (!of->log) { |
3497
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
871 |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
872 /* |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
873 * Use non-blocking open() not to hang on FIFO files, etc. |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
874 * This flag has no effect on a regular files. |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
875 */ |
ac281bc4c187
use non-blocking open() not to hang on FIFO files, etc.
Igor Sysoev <igor@sysoev.ru>
parents:
3178
diff
changeset
|
876 |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
877 fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
878 NGX_FILE_OPEN, 0, log); |
2072 | 879 |
880 } else { | |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
881 fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
882 NGX_FILE_CREATE_OR_OPEN, |
4479
5e6436812c9a
Disable symlinks: cleanup error handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4477
diff
changeset
|
883 NGX_FILE_DEFAULT_ACCESS, log); |
2072 | 884 } |
1453 | 885 |
886 if (fd == NGX_INVALID_FILE) { | |
4477
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
887 of->fd = NGX_INVALID_FILE; |
7033faf6dc3c
Added disable_symlinks directive.
Andrey Belov <defan@nginx.com>
parents:
4476
diff
changeset
|
888 return NGX_ERROR; |
1453 | 889 } |
890 | |
891 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | |
892 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
893 ngx_fd_info_n " \"%V\" failed", name); |
1453 | 894 |
895 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
896 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
897 ngx_close_file_n " \"%V\" failed", name); |
1453 | 898 } |
899 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
900 of->fd = NGX_INVALID_FILE; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
901 |
1453 | 902 return NGX_ERROR; |
903 } | |
904 | |
905 if (ngx_is_dir(&fi)) { | |
906 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
907 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
908 ngx_close_file_n " \"%V\" failed", name); |
1453 | 909 } |
910 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
911 of->fd = NGX_INVALID_FILE; |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
912 |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
913 } else { |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
914 of->fd = fd; |
2129 | 915 |
3178 | 916 if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { |
917 if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { | |
918 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
919 ngx_read_ahead_n " \"%V\" failed", name); |
3178 | 920 } |
921 } | |
922 | |
2129 | 923 if (of->directio <= ngx_file_size(&fi)) { |
3164
b1b1775698d5
uniform ngx_directio_on/off() interface with other file functions
Igor Sysoev <igor@sysoev.ru>
parents:
2934
diff
changeset
|
924 if (ngx_directio_on(fd) == NGX_FILE_ERROR) { |
2129 | 925 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
4476
94ef9d25ec5b
Changed ngx_open_and_stat_file() to use ngx_str_t.
Andrey Belov <defan@nginx.com>
parents:
4412
diff
changeset
|
926 ngx_directio_on_n " \"%V\" failed", name); |
2231
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
927 |
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
928 } else { |
8564129d49b6
*) handle unaligned file part for directio
Igor Sysoev <igor@sysoev.ru>
parents:
2129
diff
changeset
|
929 of->is_directio = 1; |
2129 | 930 } |
931 } | |
1453 | 932 } |
933 | |
2069
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
934 done: |
23930ccd2642
use ngx_file_info() and test uniq if file is already open
Igor Sysoev <igor@sysoev.ru>
parents:
2063
diff
changeset
|
935 |
1453 | 936 of->uniq = ngx_file_uniq(&fi); |
937 of->mtime = ngx_file_mtime(&fi); | |
938 of->size = ngx_file_size(&fi); | |
3899
e7cd13b7f759
Use more precise stat.st_blocks to account cache size on Unix
Igor Sysoev <igor@sysoev.ru>
parents:
3497
diff
changeset
|
939 of->fs_size = ngx_file_fs_size(&fi); |
1453 | 940 of->is_dir = ngx_is_dir(&fi); |
941 of->is_file = ngx_is_file(&fi); | |
942 of->is_link = ngx_is_link(&fi); | |
943 of->is_exec = ngx_is_exec(&fi); | |
944 | |
945 return NGX_OK; | |
946 } | |
947 | |
948 | |
1775 | 949 /* |
950 * we ignore any possible event setting error and | |
951 * fallback to usual periodic file retests | |
952 */ | |
953 | |
954 static void | |
955 ngx_open_file_add_event(ngx_open_file_cache_t *cache, | |
956 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) | |
957 { | |
958 ngx_open_file_cache_event_t *fev; | |
959 | |
960 if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) | |
961 || !of->events | |
962 || file->event | |
963 || of->fd == NGX_INVALID_FILE | |
964 || file->uses < of->min_uses) | |
965 { | |
966 return; | |
967 } | |
968 | |
2070 | 969 file->use_event = 0; |
970 | |
1775 | 971 file->event = ngx_calloc(sizeof(ngx_event_t), log); |
972 if (file->event== NULL) { | |
973 return; | |
974 } | |
975 | |
976 fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); | |
977 if (fev == NULL) { | |
978 ngx_free(file->event); | |
979 file->event = NULL; | |
980 return; | |
981 } | |
982 | |
983 fev->fd = of->fd; | |
984 fev->file = file; | |
985 fev->cache = cache; | |
986 | |
987 file->event->handler = ngx_open_file_cache_remove; | |
988 file->event->data = fev; | |
989 | |
990 /* | |
991 * although vnode event may be called while ngx_cycle->poll | |
992 * destruction, however, cleanup procedures are run before any | |
993 * memory freeing and events will be canceled. | |
994 */ | |
995 | |
996 file->event->log = ngx_cycle->log; | |
997 | |
998 if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) | |
999 != NGX_OK) | |
1000 { | |
1001 ngx_free(file->event->data); | |
1002 ngx_free(file->event); | |
1003 file->event = NULL; | |
1004 return; | |
1005 } | |
1006 | |
1007 /* | |
2071 | 1008 * we do not set file->use_event here because there may be a race |
1009 * condition: a file may be deleted between opening the file and | |
1010 * adding event, so we rely upon event notification only after | |
1011 * one file revalidation on next file access | |
1775 | 1012 */ |
1013 | |
1014 return; | |
1015 } | |
1016 | |
1017 | |
1453 | 1018 static void |
1019 ngx_open_file_cleanup(void *data) | |
1020 { | |
1021 ngx_open_file_cache_cleanup_t *c = data; | |
1022 | |
1023 c->file->count--; | |
1024 | |
1772 | 1025 ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log); |
1453 | 1026 |
1027 /* drop one or two expired open files */ | |
1028 ngx_expire_old_cached_files(c->cache, 1, c->log); | |
1029 } | |
1030 | |
1031 | |
1032 static void | |
1033 ngx_close_cached_file(ngx_open_file_cache_t *cache, | |
1772 | 1034 ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log) |
1453 | 1035 { |
1772 | 1036 ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0, |
1037 "close cached open file: %s, fd:%d, c:%d, u:%d, %d", | |
1038 file->name, file->fd, file->count, file->uses, file->close); | |
1453 | 1039 |
1040 if (!file->close) { | |
1041 | |
1042 file->accessed = ngx_time(); | |
1043 | |
1765 | 1044 ngx_queue_remove(&file->queue); |
1453 | 1045 |
1765 | 1046 ngx_queue_insert_head(&cache->expire_queue, &file->queue); |
1453 | 1047 |
1772 | 1048 if (file->uses >= min_uses || file->count) { |
1049 return; | |
1050 } | |
1453 | 1051 } |
1052 | |
1775 | 1053 ngx_open_file_del_event(file); |
1453 | 1054 |
1055 if (file->count) { | |
1056 return; | |
1057 } | |
1058 | |
1772 | 1059 if (file->fd != NGX_INVALID_FILE) { |
1060 | |
1061 if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { | |
1062 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
1063 ngx_close_file_n " \"%s\" failed", file->name); | |
1064 } | |
1065 | |
1066 file->fd = NGX_INVALID_FILE; | |
1067 } | |
1068 | |
1069 if (!file->close) { | |
1070 return; | |
1453 | 1071 } |
1072 | |
1073 ngx_free(file->name); | |
1074 ngx_free(file); | |
1075 } | |
1076 | |
1077 | |
1078 static void | |
1775 | 1079 ngx_open_file_del_event(ngx_cached_open_file_t *file) |
1080 { | |
1081 if (file->event == NULL) { | |
1082 return; | |
1083 } | |
1084 | |
1085 (void) ngx_del_event(file->event, NGX_VNODE_EVENT, | |
1086 file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); | |
1087 | |
1088 ngx_free(file->event->data); | |
1089 ngx_free(file->event); | |
1090 file->event = NULL; | |
1091 file->use_event = 0; | |
1092 } | |
1093 | |
1094 | |
1095 static void | |
1453 | 1096 ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, |
1097 ngx_log_t *log) | |
1098 { | |
1099 time_t now; | |
1765 | 1100 ngx_queue_t *q; |
1453 | 1101 ngx_cached_open_file_t *file; |
1102 | |
1103 now = ngx_time(); | |
1104 | |
1105 /* | |
1106 * n == 1 deletes one or two inactive files | |
1107 * n == 0 deletes least recently used file by force | |
1108 * and one or two inactive files | |
1109 */ | |
1110 | |
1111 while (n < 3) { | |
1112 | |
1765 | 1113 if (ngx_queue_empty(&cache->expire_queue)) { |
1453 | 1114 return; |
1115 } | |
1116 | |
1765 | 1117 q = ngx_queue_last(&cache->expire_queue); |
1118 | |
1119 file = ngx_queue_data(q, ngx_cached_open_file_t, queue); | |
1120 | |
1453 | 1121 if (n++ != 0 && now - file->accessed <= cache->inactive) { |
1122 return; | |
1123 } | |
1124 | |
1765 | 1125 ngx_queue_remove(q); |
1453 | 1126 |
1127 ngx_rbtree_delete(&cache->rbtree, &file->node); | |
1128 | |
1129 cache->current--; | |
1130 | |
1131 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
1132 "expire cached open file: %s", file->name); | |
1133 | |
1134 if (!file->err && !file->is_dir) { | |
1135 file->close = 1; | |
1772 | 1136 ngx_close_cached_file(cache, file, 0, log); |
1453 | 1137 |
1138 } else { | |
1139 ngx_free(file->name); | |
1140 ngx_free(file); | |
1141 } | |
1142 } | |
1143 } | |
1144 | |
1145 | |
1146 static void | |
1147 ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | |
1148 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) | |
1149 { | |
1150 ngx_rbtree_node_t **p; | |
1151 ngx_cached_open_file_t *file, *file_temp; | |
1152 | |
1153 for ( ;; ) { | |
1154 | |
1155 if (node->key < temp->key) { | |
1156 | |
1157 p = &temp->left; | |
1158 | |
1159 } else if (node->key > temp->key) { | |
1160 | |
1161 p = &temp->right; | |
1162 | |
1163 } else { /* node->key == temp->key */ | |
1164 | |
1165 file = (ngx_cached_open_file_t *) node; | |
1166 file_temp = (ngx_cached_open_file_t *) temp; | |
1167 | |
1168 p = (ngx_strcmp(file->name, file_temp->name) < 0) | |
1169 ? &temp->left : &temp->right; | |
1170 } | |
1171 | |
1172 if (*p == sentinel) { | |
1173 break; | |
1174 } | |
1175 | |
1176 temp = *p; | |
1177 } | |
1178 | |
1179 *p = node; | |
1180 node->parent = temp; | |
1181 node->left = sentinel; | |
1182 node->right = sentinel; | |
1183 ngx_rbt_red(node); | |
1184 } | |
1185 | |
1186 | |
1775 | 1187 static ngx_cached_open_file_t * |
1188 ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, | |
1189 uint32_t hash) | |
1190 { | |
1191 ngx_int_t rc; | |
1192 ngx_rbtree_node_t *node, *sentinel; | |
1193 ngx_cached_open_file_t *file; | |
1194 | |
1195 node = cache->rbtree.root; | |
1196 sentinel = cache->rbtree.sentinel; | |
1197 | |
1198 while (node != sentinel) { | |
1199 | |
1200 if (hash < node->key) { | |
1201 node = node->left; | |
1202 continue; | |
1203 } | |
1204 | |
1205 if (hash > node->key) { | |
1206 node = node->right; | |
1207 continue; | |
1208 } | |
1209 | |
1210 /* hash == node->key */ | |
1211 | |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4493
diff
changeset
|
1212 file = (ngx_cached_open_file_t *) node; |
1775 | 1213 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4493
diff
changeset
|
1214 rc = ngx_strcmp(name->data, file->name); |
1775 | 1215 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4493
diff
changeset
|
1216 if (rc == 0) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4493
diff
changeset
|
1217 return file; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4493
diff
changeset
|
1218 } |
1775 | 1219 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4493
diff
changeset
|
1220 node = (rc < 0) ? node->left : node->right; |
1775 | 1221 } |
1222 | |
1223 return NULL; | |
1224 } | |
1225 | |
1226 | |
1453 | 1227 static void |
1228 ngx_open_file_cache_remove(ngx_event_t *ev) | |
1229 { | |
1230 ngx_cached_open_file_t *file; | |
1231 ngx_open_file_cache_event_t *fev; | |
1232 | |
1233 fev = ev->data; | |
1234 file = fev->file; | |
1235 | |
1765 | 1236 ngx_queue_remove(&file->queue); |
1453 | 1237 |
1238 ngx_rbtree_delete(&fev->cache->rbtree, &file->node); | |
1239 | |
1240 fev->cache->current--; | |
1241 | |
1242 /* NGX_ONESHOT_EVENT was already deleted */ | |
1243 file->event = NULL; | |
2070 | 1244 file->use_event = 0; |
1453 | 1245 |
1246 file->close = 1; | |
1247 | |
1772 | 1248 ngx_close_cached_file(fev->cache, file, 0, ev->log); |
1453 | 1249 |
1250 /* free memory only when fev->cache and fev->file are already not needed */ | |
1251 | |
1252 ngx_free(ev->data); | |
1253 ngx_free(ev); | |
1254 } |