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