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