0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9
|
|
10
|
44
|
11 static ngx_atomic_uint_t ngx_temp_number;
|
250
|
12 static ngx_atomic_uint_t ngx_random_number;
|
0
|
13
|
|
14
|
42
|
15 ssize_t
|
|
16 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
|
0
|
17 {
|
16
|
18 ngx_int_t rc;
|
0
|
19
|
|
20 if (tf->file.fd == NGX_INVALID_FILE) {
|
|
21 rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
|
278
|
22 tf->persistent, tf->clean, tf->access);
|
0
|
23
|
|
24 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
|
|
25 return rc;
|
|
26 }
|
|
27
|
216
|
28 if (tf->log_level) {
|
|
29 ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
|
186
|
30 tf->warn, &tf->file.name);
|
0
|
31 }
|
|
32 }
|
|
33
|
|
34 return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
|
|
35 }
|
|
36
|
|
37
|
42
|
38 ngx_int_t
|
|
39 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
|
278
|
40 ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
|
0
|
41 {
|
282
|
42 uint32_t n;
|
58
|
43 ngx_err_t err;
|
112
|
44 ngx_pool_cleanup_t *cln;
|
|
45 ngx_pool_cleanup_file_t *clnf;
|
0
|
46
|
282
|
47 file->name.len = path->name.len + 1 + path->len + 10;
|
0
|
48
|
382
|
49 file->name.data = ngx_pnalloc(pool, file->name.len + 1);
|
50
|
50 if (file->name.data == NULL) {
|
16
|
51 return NGX_ERROR;
|
|
52 }
|
0
|
53
|
|
54 #if 0
|
|
55 for (i = 0; i < file->name.len; i++) {
|
|
56 file->name.data[i] = 'X';
|
|
57 }
|
|
58 #endif
|
|
59
|
|
60 ngx_memcpy(file->name.data, path->name.data, path->name.len);
|
|
61
|
282
|
62 n = (uint32_t) ngx_next_temp_number(0);
|
0
|
63
|
356
|
64 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
|
|
65 if (cln == NULL) {
|
|
66 return NGX_ERROR;
|
|
67 }
|
|
68
|
0
|
69 for ( ;; ) {
|
66
|
70 (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len,
|
282
|
71 "%010uD%Z", n);
|
0
|
72
|
356
|
73 ngx_create_hashed_filename(path, file->name.data, file->name.len);
|
0
|
74
|
356
|
75 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
76 "hashed path: %s", file->name.data);
|
112
|
77
|
276
|
78 file->fd = ngx_open_tempfile(file->name.data, persistent, access);
|
0
|
79
|
|
80 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
81 "temp fd:%d", file->fd);
|
|
82
|
|
83 if (file->fd != NGX_INVALID_FILE) {
|
112
|
84
|
278
|
85 cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
|
112
|
86 clnf = cln->data;
|
58
|
87
|
112
|
88 clnf->fd = file->fd;
|
|
89 clnf->name = file->name.data;
|
|
90 clnf->log = pool->log;
|
58
|
91
|
0
|
92 return NGX_OK;
|
|
93 }
|
|
94
|
|
95 err = ngx_errno;
|
|
96
|
|
97 if (err == NGX_EEXIST) {
|
282
|
98 n = (uint32_t) ngx_next_temp_number(1);
|
0
|
99 continue;
|
|
100 }
|
|
101
|
|
102 if ((path->level[0] == 0)
|
|
103 || (err != NGX_ENOENT
|
10
|
104 #if (NGX_WIN32)
|
0
|
105 && err != NGX_ENOTDIR
|
|
106 #endif
|
16
|
107 ))
|
|
108 {
|
0
|
109 ngx_log_error(NGX_LOG_CRIT, file->log, err,
|
|
110 ngx_open_tempfile_n " \"%s\" failed",
|
|
111 file->name.data);
|
|
112 return NGX_ERROR;
|
|
113 }
|
|
114
|
|
115 if (ngx_create_path(file, path) == NGX_ERROR) {
|
|
116 return NGX_ERROR;
|
|
117 }
|
|
118 }
|
|
119 }
|
|
120
|
|
121
|
42
|
122 void
|
356
|
123 ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
|
0
|
124 {
|
356
|
125 size_t i, level;
|
|
126 ngx_uint_t n;
|
0
|
127
|
356
|
128 i = path->name.len + 1;
|
0
|
129
|
356
|
130 file[path->name.len + path->len] = '/';
|
0
|
131
|
356
|
132 for (n = 0; n < 3; n++) {
|
|
133 level = path->level[n];
|
0
|
134
|
|
135 if (level == 0) {
|
|
136 break;
|
|
137 }
|
|
138
|
356
|
139 len -= level;
|
|
140 file[i - 1] = '/';
|
|
141 ngx_memcpy(&file[i], &file[len], level);
|
|
142 i += level + 1;
|
0
|
143 }
|
|
144 }
|
|
145
|
|
146
|
42
|
147 ngx_int_t
|
|
148 ngx_create_path(ngx_file_t *file, ngx_path_t *path)
|
0
|
149 {
|
66
|
150 size_t pos;
|
|
151 ngx_err_t err;
|
|
152 ngx_uint_t i;
|
0
|
153
|
|
154 pos = path->name.len;
|
|
155
|
|
156 for (i = 0; i < 3; i++) {
|
|
157 if (path->level[i] == 0) {
|
|
158 break;
|
|
159 }
|
|
160
|
|
161 pos += path->level[i] + 1;
|
|
162
|
|
163 file->name.data[pos] = '\0';
|
|
164
|
|
165 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
166 "temp file: \"%s\"", file->name.data);
|
|
167
|
218
|
168 if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
|
0
|
169 err = ngx_errno;
|
|
170 if (err != NGX_EEXIST) {
|
|
171 ngx_log_error(NGX_LOG_CRIT, file->log, err,
|
|
172 ngx_create_dir_n " \"%s\" failed",
|
|
173 file->name.data);
|
|
174 return NGX_ERROR;
|
|
175 }
|
|
176 }
|
|
177
|
|
178 file->name.data[pos] = '/';
|
|
179 }
|
|
180
|
|
181 return NGX_OK;
|
|
182 }
|
|
183
|
|
184
|
186
|
185 ngx_err_t
|
218
|
186 ngx_create_full_path(u_char *dir, ngx_uint_t access)
|
186
|
187 {
|
|
188 u_char *p, ch;
|
|
189 ngx_err_t err;
|
|
190
|
|
191 for (p = dir + 1; *p; p++) {
|
|
192 ch = *p;
|
|
193
|
|
194 if (ch != '/') {
|
|
195 continue;
|
|
196 }
|
|
197
|
|
198 *p = '\0';
|
|
199
|
218
|
200 if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
|
186
|
201 err = ngx_errno;
|
|
202 if (err != NGX_EEXIST) {
|
|
203 return err;
|
|
204 }
|
|
205 }
|
|
206
|
|
207 *p = '/';
|
|
208 }
|
|
209
|
|
210 return 0;
|
|
211 }
|
|
212
|
|
213
|
42
|
214 void
|
48
|
215 ngx_init_temp_number(void)
|
0
|
216 {
|
42
|
217 ngx_temp_number = 0;
|
250
|
218 ngx_random_number = 123456;
|
0
|
219 }
|
|
220
|
|
221
|
44
|
222 ngx_atomic_uint_t
|
42
|
223 ngx_next_temp_number(ngx_uint_t collision)
|
0
|
224 {
|
|
225 if (collision) {
|
250
|
226 ngx_temp_number += ngx_random_number;
|
0
|
227 }
|
|
228
|
|
229 return ngx_temp_number++;
|
|
230 }
|
|
231
|
|
232
|
42
|
233 char *
|
|
234 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
0
|
235 {
|
|
236 char *p = conf;
|
|
237
|
16
|
238 ssize_t level;
|
178
|
239 ngx_str_t *value;
|
0
|
240 ngx_uint_t i, n;
|
28
|
241 ngx_path_t *path, **slot;
|
0
|
242
|
16
|
243 slot = (ngx_path_t **) (p + cmd->offset);
|
0
|
244
|
16
|
245 if (*slot) {
|
0
|
246 return "is duplicate";
|
|
247 }
|
|
248
|
50
|
249 path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
|
|
250 if (path == NULL) {
|
16
|
251 return NGX_CONF_ERROR;
|
|
252 }
|
0
|
253
|
16
|
254 value = cf->args->elts;
|
0
|
255
|
|
256 path->name = value[1];
|
178
|
257
|
210
|
258 if (path->name.data[path->name.len - 1] == '/') {
|
|
259 path->name.len--;
|
|
260 }
|
|
261
|
493
|
262 if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) {
|
178
|
263 return NULL;
|
|
264 }
|
|
265
|
0
|
266 path->len = 0;
|
507
|
267 path->manager = (ngx_path_manager_pt) cmd->post;
|
16
|
268 path->conf_file = cf->conf_file->file.name.data;
|
|
269 path->line = cf->conf_file->line;
|
0
|
270
|
|
271 for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
|
|
272 level = ngx_atoi(value[n].data, value[n].len);
|
|
273 if (level == NGX_ERROR || level == 0) {
|
|
274 return "invalid value";
|
|
275 }
|
|
276
|
|
277 path->level[i] = level;
|
|
278 path->len += level + 1;
|
|
279 }
|
|
280
|
|
281 while (i < 3) {
|
|
282 path->level[i++] = 0;
|
|
283 }
|
|
284
|
28
|
285 *slot = path;
|
16
|
286
|
28
|
287 if (ngx_add_path(cf, slot) == NGX_ERROR) {
|
|
288 return NGX_CONF_ERROR;
|
|
289 }
|
|
290
|
|
291 return NGX_CONF_OK;
|
|
292 }
|
|
293
|
|
294
|
318
|
295 char *
|
503
|
296 ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
|
|
297 ngx_path_init_t *init)
|
|
298 {
|
|
299 if (*path) {
|
|
300 return NGX_CONF_OK;
|
|
301 }
|
|
302
|
|
303 if (prev) {
|
|
304 *path = prev;
|
|
305 return NGX_CONF_OK;
|
|
306 }
|
|
307
|
|
308 *path = ngx_palloc(cf->pool, sizeof(ngx_path_t));
|
|
309 if (*path == NULL) {
|
|
310 return NGX_CONF_ERROR;
|
|
311 }
|
|
312
|
|
313 (*path)->name = init->name;
|
|
314
|
|
315 if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) {
|
|
316 return NGX_CONF_ERROR;
|
|
317 }
|
|
318
|
|
319 (*path)->level[0] = init->level[0];
|
|
320 (*path)->level[1] = init->level[1];
|
|
321 (*path)->level[2] = init->level[2];
|
|
322
|
|
323 (*path)->len = init->level[0] + (init->level[0] ? 1 : 0)
|
|
324 + init->level[1] + (init->level[1] ? 1 : 0)
|
|
325 + init->level[2] + (init->level[2] ? 1 : 0);
|
|
326
|
507
|
327 (*path)->manager = NULL;
|
503
|
328 (*path)->conf_file = NULL;
|
|
329
|
|
330 if (ngx_add_path(cf, path) != NGX_OK) {
|
|
331 return NGX_CONF_ERROR;
|
|
332 }
|
|
333
|
|
334 return NGX_CONF_OK;
|
|
335 }
|
|
336
|
|
337
|
|
338 char *
|
318
|
339 ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|
340 {
|
|
341 char *confp = conf;
|
|
342
|
|
343 u_char *p;
|
|
344 ngx_str_t *value;
|
|
345 ngx_uint_t i, right, shift, *access;
|
|
346
|
|
347 access = (ngx_uint_t *) (confp + cmd->offset);
|
320
|
348
|
318
|
349 if (*access != NGX_CONF_UNSET_UINT) {
|
|
350 return "is duplicate";
|
|
351 }
|
320
|
352
|
318
|
353 value = cf->args->elts;
|
|
354
|
|
355 *access = 0600;
|
|
356
|
|
357 for (i = 1; i < cf->args->nelts; i++) {
|
|
358
|
|
359 p = value[i].data;
|
|
360
|
|
361 if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
|
|
362 shift = 6;
|
|
363 p += sizeof("user:") - 1;
|
|
364
|
|
365 } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
|
|
366 shift = 3;
|
|
367 p += sizeof("group:") - 1;
|
|
368
|
|
369 } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
|
|
370 shift = 0;
|
|
371 p += sizeof("all:") - 1;
|
|
372
|
|
373 } else {
|
|
374 goto invalid;
|
|
375 }
|
|
376
|
|
377 if (ngx_strcmp(p, "rw") == 0) {
|
|
378 right = 6;
|
|
379
|
|
380 } else if (ngx_strcmp(p, "r") == 0) {
|
|
381 right = 4;
|
|
382
|
|
383 } else {
|
|
384 goto invalid;
|
|
385 }
|
|
386
|
|
387 *access |= right << shift;
|
|
388 }
|
320
|
389
|
318
|
390 return NGX_CONF_OK;
|
|
391
|
|
392 invalid:
|
|
393
|
|
394 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\"", &value[i]);
|
|
395
|
|
396 return NGX_CONF_ERROR;
|
|
397 }
|
|
398
|
|
399
|
42
|
400 ngx_int_t
|
|
401 ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
|
28
|
402 {
|
|
403 ngx_uint_t i, n;
|
|
404 ngx_path_t *path, **p;
|
|
405
|
|
406 path = *slot;
|
|
407
|
|
408 p = cf->cycle->pathes.elts;
|
16
|
409 for (i = 0; i < cf->cycle->pathes.nelts; i++) {
|
28
|
410 if (p[i]->name.len == path->name.len
|
|
411 && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
|
16
|
412 {
|
|
413 for (n = 0; n < 3; n++) {
|
28
|
414 if (p[i]->level[n] != path->level[n]) {
|
|
415 if (path->conf_file == NULL) {
|
30
|
416 if (p[i]->conf_file == NULL) {
|
|
417 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
|
418 "the default path name \"%V\" has "
|
|
419 "the same name as another default path, "
|
|
420 "but the different levels, you need to "
|
|
421 "redefine one of them in http section",
|
|
422 &p[i]->name);
|
|
423 return NGX_ERROR;
|
|
424 }
|
|
425
|
28
|
426 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
|
427 "the path name \"%V\" in %s:%ui has "
|
30
|
428 "the same name as default path, but "
|
28
|
429 "the different levels, you need to "
|
|
430 "define default path in http section",
|
|
431 &p[i]->name, p[i]->conf_file, p[i]->line);
|
|
432 return NGX_ERROR;
|
|
433 }
|
|
434
|
16
|
435 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
28
|
436 "the same path name \"%V\" in %s:%ui "
|
|
437 "has the different levels than",
|
|
438 &p[i]->name, p[i]->conf_file, p[i]->line);
|
|
439 return NGX_ERROR;
|
16
|
440 }
|
|
441
|
28
|
442 if (p[i]->level[n] == 0) {
|
16
|
443 break;
|
|
444 }
|
|
445 }
|
|
446
|
28
|
447 *slot = p[i];
|
16
|
448
|
28
|
449 return NGX_OK;
|
16
|
450 }
|
|
451 }
|
|
452
|
50
|
453 p = ngx_array_push(&cf->cycle->pathes);
|
|
454 if (p == NULL) {
|
28
|
455 return NGX_ERROR;
|
16
|
456 }
|
|
457
|
28
|
458 *p = path;
|
0
|
459
|
28
|
460 return NGX_OK;
|
0
|
461 }
|
16
|
462
|
|
463
|
42
|
464 ngx_int_t
|
|
465 ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user)
|
16
|
466 {
|
|
467 ngx_err_t err;
|
|
468 ngx_uint_t i;
|
|
469 ngx_path_t **path;
|
|
470
|
|
471 path = cycle->pathes.elts;
|
|
472 for (i = 0; i < cycle->pathes.nelts; i++) {
|
|
473
|
218
|
474 if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
|
16
|
475 err = ngx_errno;
|
|
476 if (err != NGX_EEXIST) {
|
|
477 ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
|
|
478 ngx_create_dir_n " \"%s\" failed",
|
|
479 path[i]->name.data);
|
|
480 return NGX_ERROR;
|
|
481 }
|
|
482 }
|
|
483
|
66
|
484 if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
|
16
|
485 continue;
|
|
486 }
|
|
487
|
|
488 #if !(NGX_WIN32)
|
356
|
489 {
|
|
490 ngx_file_info_t fi;
|
16
|
491
|
|
492 if (ngx_file_info((const char *) path[i]->name.data, &fi) == -1) {
|
|
493 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
|
494 ngx_file_info_n " \"%s\" failed", path[i]->name.data);
|
|
495 return NGX_ERROR;
|
|
496 }
|
|
497
|
|
498 if (fi.st_uid != user) {
|
|
499 if (chown((const char *) path[i]->name.data, user, -1) == -1) {
|
|
500 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
|
501 "chown(\"%s\", %d) failed",
|
|
502 path[i]->name.data, user);
|
|
503 return NGX_ERROR;
|
|
504 }
|
|
505 }
|
|
506
|
|
507 if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
|
|
508 != (S_IRUSR|S_IWUSR|S_IXUSR))
|
|
509 {
|
|
510 fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);
|
|
511
|
|
512 if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
|
|
513 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
|
514 "chmod() \"%s\" failed", path[i]->name.data);
|
|
515 return NGX_ERROR;
|
|
516 }
|
|
517 }
|
356
|
518 }
|
16
|
519 #endif
|
|
520 }
|
|
521
|
|
522 return NGX_OK;
|
|
523 }
|
272
|
524
|
|
525
|
|
526 ngx_int_t
|
362
|
527 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
|
356
|
528 {
|
|
529 ngx_err_t err;
|
|
530
|
|
531 #if !(NGX_WIN32)
|
|
532
|
459
|
533 if (ext->access) {
|
|
534 if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
|
|
535 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
|
|
536 ngx_change_file_access_n " \"%s\" failed", src->data);
|
|
537 err = 0;
|
|
538 goto failed;
|
|
539 }
|
356
|
540 }
|
|
541
|
|
542 #endif
|
|
543
|
362
|
544 if (ext->time != -1) {
|
|
545 if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) {
|
|
546 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
|
|
547 ngx_set_file_time_n " \"%s\" failed", src->data);
|
|
548 err = 0;
|
|
549 goto failed;
|
|
550 }
|
|
551 }
|
|
552
|
356
|
553 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
|
|
554 return NGX_OK;
|
|
555 }
|
|
556
|
|
557 err = ngx_errno;
|
|
558
|
|
559 if (err == NGX_ENOENT) {
|
|
560
|
362
|
561 if (!ext->create_path) {
|
356
|
562 goto failed;
|
|
563 }
|
|
564
|
459
|
565 err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access));
|
356
|
566
|
|
567 if (err) {
|
362
|
568 ngx_log_error(NGX_LOG_CRIT, ext->log, err,
|
356
|
569 ngx_create_dir_n " \"%s\" failed", to->data);
|
|
570 err = 0;
|
|
571 goto failed;
|
|
572 }
|
|
573
|
|
574 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
|
|
575 return NGX_OK;
|
|
576 }
|
|
577
|
|
578 err = ngx_errno;
|
|
579 goto failed;
|
|
580 }
|
|
581
|
|
582 #if (NGX_WIN32)
|
|
583
|
|
584 if (err == NGX_EEXIST) {
|
362
|
585 if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) {
|
356
|
586
|
|
587 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
|
|
588 return NGX_OK;
|
|
589 }
|
|
590
|
|
591 err = ngx_errno;
|
|
592
|
|
593 } else {
|
|
594 err = 0;
|
|
595 }
|
|
596 }
|
|
597
|
|
598 #endif
|
|
599
|
|
600 failed:
|
|
601
|
366
|
602 if (ext->delete_file) {
|
356
|
603 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
|
362
|
604 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
|
356
|
605 ngx_delete_file_n " \"%s\" failed", src->data);
|
|
606 }
|
|
607 }
|
|
608
|
459
|
609 if (err && ext->log_rename_error) {
|
362
|
610 ngx_log_error(NGX_LOG_CRIT, ext->log, err,
|
356
|
611 ngx_rename_file_n " \"%s\" to \"%s\" failed",
|
|
612 src->data, to->data);
|
|
613 }
|
|
614
|
459
|
615 ext->rename_error = err;
|
|
616
|
356
|
617 return NGX_ERROR;
|
|
618 }
|
|
619
|
|
620
|
|
621 /*
|
|
622 * ctx->init_handler() - see ctx->alloc
|
|
623 * ctx->file_handler() - file handler
|
|
624 * ctx->pre_tree_handler() - handler is called before entering directory
|
|
625 * ctx->post_tree_handler() - handler is called after leaving directory
|
|
626 * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
|
|
627 *
|
|
628 * ctx->data - some data structure, it may be the same on all levels, or
|
|
629 * reallocated if ctx->alloc is nonzero
|
|
630 *
|
|
631 * ctx->alloc - a size of data structure that is allocated at every level
|
|
632 * and is initilialized by ctx->init_handler()
|
|
633 *
|
|
634 * ctx->log - a log
|
|
635 *
|
|
636 * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
|
|
637 */
|
|
638
|
|
639 ngx_int_t
|
272
|
640 ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
|
|
641 {
|
|
642 void *data, *prev;
|
|
643 u_char *p, *name;
|
|
644 size_t len;
|
|
645 ngx_int_t rc;
|
|
646 ngx_err_t err;
|
|
647 ngx_str_t file, buf;
|
|
648 ngx_dir_t dir;
|
|
649
|
|
650 buf.len = 0;
|
|
651 buf.data = NULL;
|
|
652
|
|
653 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
654 "walk tree \"%V\"", tree);
|
|
655
|
|
656 if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
|
|
657 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
658 ngx_open_dir_n " \"%s\" failed", tree->data);
|
|
659 return NGX_ERROR;
|
|
660 }
|
|
661
|
|
662 prev = ctx->data;
|
|
663
|
276
|
664 if (ctx->alloc) {
|
|
665 data = ngx_alloc(ctx->alloc, ctx->log);
|
272
|
666 if (data == NULL) {
|
|
667 goto failed;
|
|
668 }
|
|
669
|
|
670 if (ctx->init_handler(data, prev) == NGX_ABORT) {
|
|
671 goto failed;
|
|
672 }
|
|
673
|
|
674 ctx->data = data;
|
322
|
675
|
|
676 } else {
|
|
677 data = NULL;
|
272
|
678 }
|
|
679
|
|
680 for ( ;; ) {
|
|
681
|
|
682 ngx_set_errno(0);
|
|
683
|
|
684 if (ngx_read_dir(&dir) == NGX_ERROR) {
|
|
685 err = ngx_errno;
|
|
686
|
|
687 if (err == NGX_ENOMOREFILES) {
|
|
688 rc = NGX_OK;
|
|
689
|
|
690 } else {
|
|
691 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
|
|
692 ngx_read_dir_n " \"%s\" failed", tree->data);
|
|
693 rc = NGX_ERROR;
|
|
694 }
|
|
695
|
|
696 goto done;
|
|
697 }
|
|
698
|
|
699 len = ngx_de_namelen(&dir);
|
|
700 name = ngx_de_name(&dir);
|
|
701
|
|
702 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
703 "tree name %uz:\"%s\"", len, name);
|
|
704
|
|
705 if (len == 1 && name[0] == '.') {
|
|
706 continue;
|
|
707 }
|
|
708
|
|
709 if (len == 2 && name[0] == '.' && name[1] == '.') {
|
|
710 continue;
|
|
711 }
|
|
712
|
|
713 file.len = tree->len + 1 + len;
|
|
714
|
|
715 if (file.len + NGX_DIR_MASK_LEN > buf.len) {
|
|
716
|
|
717 if (buf.len) {
|
|
718 ngx_free(buf.data);
|
|
719 }
|
|
720
|
|
721 buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
|
|
722
|
|
723 buf.data = ngx_alloc(buf.len + 1, ctx->log);
|
|
724 if (buf.data == NULL) {
|
|
725 goto failed;
|
|
726 }
|
|
727 }
|
|
728
|
|
729 p = ngx_cpymem(buf.data, tree->data, tree->len);
|
|
730 *p++ = '/';
|
|
731 ngx_memcpy(p, name, len + 1);
|
|
732
|
|
733 file.data = buf.data;
|
|
734
|
|
735 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
736 "tree path \"%s\"", file.data);
|
|
737
|
|
738 if (!dir.valid_info) {
|
|
739 if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
|
|
740 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
741 ngx_de_info_n " \"%s\" failed", file.data);
|
|
742 continue;
|
|
743 }
|
|
744 }
|
|
745
|
|
746 if (ngx_de_is_file(&dir)) {
|
|
747
|
|
748 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
749 "tree file \"%s\"", file.data);
|
|
750
|
276
|
751 ctx->size = ngx_de_size(&dir);
|
|
752 ctx->access = ngx_de_access(&dir);
|
|
753 ctx->mtime = ngx_de_mtime(&dir);
|
|
754
|
272
|
755 if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
|
|
756 goto failed;
|
|
757 }
|
|
758
|
|
759 } else if (ngx_de_is_dir(&dir)) {
|
|
760
|
|
761 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
762 "tree enter dir \"%s\"", file.data);
|
|
763
|
276
|
764 ctx->access = ngx_de_access(&dir);
|
|
765 ctx->mtime = ngx_de_mtime(&dir);
|
|
766
|
272
|
767 if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) {
|
|
768 goto failed;
|
|
769 }
|
|
770
|
|
771 if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
|
|
772 goto failed;
|
|
773 }
|
|
774
|
276
|
775 ctx->access = ngx_de_access(&dir);
|
|
776 ctx->mtime = ngx_de_mtime(&dir);
|
|
777
|
272
|
778 if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
|
|
779 goto failed;
|
|
780 }
|
|
781
|
|
782 } else {
|
|
783
|
|
784 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
785 "tree special \"%s\"", file.data);
|
|
786
|
|
787 if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
|
|
788 goto failed;
|
|
789 }
|
|
790 }
|
|
791 }
|
|
792
|
|
793 failed:
|
|
794
|
|
795 rc = NGX_ABORT;
|
|
796
|
|
797 done:
|
|
798
|
|
799 if (buf.len) {
|
|
800 ngx_free(buf.data);
|
|
801 }
|
|
802
|
322
|
803 if (data) {
|
|
804 ngx_free(data);
|
272
|
805 ctx->data = prev;
|
|
806 }
|
|
807
|
|
808 if (ngx_close_dir(&dir) == NGX_ERROR) {
|
|
809 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
810 ngx_close_dir_n " \"%s\" failed", tree->data);
|
|
811 }
|
|
812
|
|
813 return rc;
|
|
814 }
|