Annotation of embedaddon/nginx/src/core/ngx_file.c, revision 1.1.1.1
1.1 misho 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>