3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
11 static ngx_atomic_t temp_number
= 0;
12 ngx_atomic_t
*ngx_temp_number
= &temp_number
;
13 ngx_atomic_int_t ngx_random_number
= 123456;
17 ngx_write_chain_to_temp_file(ngx_temp_file_t
*tf
, ngx_chain_t
*chain
)
21 if (tf
->file
.fd
== NGX_INVALID_FILE
) {
22 rc
= ngx_create_temp_file(&tf
->file
, tf
->path
, tf
->pool
,
23 tf
->persistent
, tf
->clean
, tf
->access
);
25 if (rc
== NGX_ERROR
|| rc
== NGX_AGAIN
) {
30 ngx_log_error(tf
->log_level
, tf
->file
.log
, 0, "%s %V",
31 tf
->warn
, &tf
->file
.name
);
35 return ngx_write_chain_to_file(&tf
->file
, chain
, tf
->offset
, tf
->pool
);
40 ngx_create_temp_file(ngx_file_t
*file
, ngx_path_t
*path
, ngx_pool_t
*pool
,
41 ngx_uint_t persistent
, ngx_uint_t clean
, ngx_uint_t access
)
45 ngx_pool_cleanup_t
*cln
;
46 ngx_pool_cleanup_file_t
*clnf
;
48 file
->name
.len
= path
->name
.len
+ 1 + path
->len
+ 10;
50 file
->name
.data
= ngx_pnalloc(pool
, file
->name
.len
+ 1);
51 if (file
->name
.data
== NULL
) {
56 for (i
= 0; i
< file
->name
.len
; i
++) {
57 file
->name
.data
[i
] = 'X';
61 ngx_memcpy(file
->name
.data
, path
->name
.data
, path
->name
.len
);
63 n
= (uint32_t) ngx_next_temp_number(0);
65 cln
= ngx_pool_cleanup_add(pool
, sizeof(ngx_pool_cleanup_file_t
));
71 (void) ngx_sprintf(file
->name
.data
+ path
->name
.len
+ 1 + path
->len
,
74 ngx_create_hashed_filename(path
, file
->name
.data
, file
->name
.len
);
76 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, file
->log
, 0,
77 "hashed path: %s", file
->name
.data
);
79 file
->fd
= ngx_open_tempfile(file
->name
.data
, persistent
, access
);
81 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, file
->log
, 0,
82 "temp fd:%d", file
->fd
);
84 if (file
->fd
!= NGX_INVALID_FILE
) {
86 cln
->handler
= clean
? ngx_pool_delete_file
: ngx_pool_cleanup_file
;
90 clnf
->name
= file
->name
.data
;
91 clnf
->log
= pool
->log
;
98 if (err
== NGX_EEXIST
) {
99 n
= (uint32_t) ngx_next_temp_number(1);
103 if ((path
->level
[0] == 0) || (err
!= NGX_ENOPATH
)) {
104 ngx_log_error(NGX_LOG_CRIT
, file
->log
, err
,
105 ngx_open_tempfile_n
" \"%s\" failed",
110 if (ngx_create_path(file
, path
) == NGX_ERROR
) {
118 ngx_create_hashed_filename(ngx_path_t
*path
, u_char
*file
, size_t len
)
123 i
= path
->name
.len
+ 1;
125 file
[path
->name
.len
+ path
->len
] = '/';
127 for (n
= 0; n
< 3; n
++) {
128 level
= path
->level
[n
];
136 ngx_memcpy(&file
[i
], &file
[len
], level
);
143 ngx_create_path(ngx_file_t
*file
, ngx_path_t
*path
)
149 pos
= path
->name
.len
;
151 for (i
= 0; i
< 3; i
++) {
152 if (path
->level
[i
] == 0) {
156 pos
+= path
->level
[i
] + 1;
158 file
->name
.data
[pos
] = '\0';
160 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, file
->log
, 0,
161 "temp file: \"%s\"", file
->name
.data
);
163 if (ngx_create_dir(file
->name
.data
, 0700) == NGX_FILE_ERROR
) {
165 if (err
!= NGX_EEXIST
) {
166 ngx_log_error(NGX_LOG_CRIT
, file
->log
, err
,
167 ngx_create_dir_n
" \"%s\" failed",
173 file
->name
.data
[pos
] = '/';
181 ngx_create_full_path(u_char
*dir
, ngx_uint_t access
)
194 for ( /* void */ ; *p
; p
++) {
203 if (ngx_create_dir(dir
, access
) == NGX_FILE_ERROR
) {
225 ngx_next_temp_number(ngx_uint_t collision
)
227 ngx_atomic_uint_t n
, add
;
229 add
= collision
? ngx_random_number
: 1;
231 n
= ngx_atomic_fetch_add(ngx_temp_number
, add
);
238 ngx_conf_set_path_slot(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
245 ngx_path_t
*path
, **slot
;
247 slot
= (ngx_path_t
**) (p
+ cmd
->offset
);
250 return "is duplicate";
253 path
= ngx_pcalloc(cf
->pool
, sizeof(ngx_path_t
));
255 return NGX_CONF_ERROR
;
258 value
= cf
->args
->elts
;
260 path
->name
= value
[1];
262 if (path
->name
.data
[path
->name
.len
- 1] == '/') {
266 if (ngx_conf_full_name(cf
->cycle
, &path
->name
, 0) != NGX_OK
) {
271 path
->manager
= NULL
;
273 path
->conf_file
= cf
->conf_file
->file
.name
.data
;
274 path
->line
= cf
->conf_file
->line
;
276 for (i
= 0, n
= 2; n
< cf
->args
->nelts
; i
++, n
++) {
277 level
= ngx_atoi(value
[n
].data
, value
[n
].len
);
278 if (level
== NGX_ERROR
|| level
== 0) {
279 return "invalid value";
282 path
->level
[i
] = level
;
283 path
->len
+= level
+ 1;
287 path
->level
[i
++] = 0;
292 if (ngx_add_path(cf
, slot
) == NGX_ERROR
) {
293 return NGX_CONF_ERROR
;
301 ngx_conf_merge_path_value(ngx_conf_t
*cf
, ngx_path_t
**path
, ngx_path_t
*prev
,
302 ngx_path_init_t
*init
)
313 *path
= ngx_palloc(cf
->pool
, sizeof(ngx_path_t
));
315 return NGX_CONF_ERROR
;
318 (*path
)->name
= init
->name
;
320 if (ngx_conf_full_name(cf
->cycle
, &(*path
)->name
, 0) != NGX_OK
) {
321 return NGX_CONF_ERROR
;
324 (*path
)->level
[0] = init
->level
[0];
325 (*path
)->level
[1] = init
->level
[1];
326 (*path
)->level
[2] = init
->level
[2];
328 (*path
)->len
= init
->level
[0] + (init
->level
[0] ? 1 : 0)
329 + init
->level
[1] + (init
->level
[1] ? 1 : 0)
330 + init
->level
[2] + (init
->level
[2] ? 1 : 0);
332 (*path
)->manager
= NULL
;
333 (*path
)->loader
= NULL
;
334 (*path
)->conf_file
= NULL
;
336 if (ngx_add_path(cf
, path
) != NGX_OK
) {
337 return NGX_CONF_ERROR
;
345 ngx_conf_set_access_slot(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
351 ngx_uint_t i
, right
, shift
, *access
;
353 access
= (ngx_uint_t
*) (confp
+ cmd
->offset
);
355 if (*access
!= NGX_CONF_UNSET_UINT
) {
356 return "is duplicate";
359 value
= cf
->args
->elts
;
363 for (i
= 1; i
< cf
->args
->nelts
; i
++) {
367 if (ngx_strncmp(p
, "user:", sizeof("user:") - 1) == 0) {
369 p
+= sizeof("user:") - 1;
371 } else if (ngx_strncmp(p
, "group:", sizeof("group:") - 1) == 0) {
373 p
+= sizeof("group:") - 1;
375 } else if (ngx_strncmp(p
, "all:", sizeof("all:") - 1) == 0) {
377 p
+= sizeof("all:") - 1;
383 if (ngx_strcmp(p
, "rw") == 0) {
386 } else if (ngx_strcmp(p
, "r") == 0) {
393 *access
|= right
<< shift
;
400 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0, "invalid value \"%V\"", &value
[i
]);
402 return NGX_CONF_ERROR
;
407 ngx_add_path(ngx_conf_t
*cf
, ngx_path_t
**slot
)
410 ngx_path_t
*path
, **p
;
414 p
= cf
->cycle
->pathes
.elts
;
415 for (i
= 0; i
< cf
->cycle
->pathes
.nelts
; i
++) {
416 if (p
[i
]->name
.len
== path
->name
.len
417 && ngx_strcmp(p
[i
]->name
.data
, path
->name
.data
) == 0)
419 for (n
= 0; n
< 3; n
++) {
420 if (p
[i
]->level
[n
] != path
->level
[n
]) {
421 if (path
->conf_file
== NULL
) {
422 if (p
[i
]->conf_file
== NULL
) {
423 ngx_log_error(NGX_LOG_EMERG
, cf
->log
, 0,
424 "the default path name \"%V\" has "
425 "the same name as another default path, "
426 "but the different levels, you need to "
427 "redefine one of them in http section",
432 ngx_log_error(NGX_LOG_EMERG
, cf
->log
, 0,
433 "the path name \"%V\" in %s:%ui has "
434 "the same name as default path, but "
435 "the different levels, you need to "
436 "define default path in http section",
437 &p
[i
]->name
, p
[i
]->conf_file
, p
[i
]->line
);
441 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
442 "the same path name \"%V\" in %s:%ui "
443 "has the different levels than",
444 &p
[i
]->name
, p
[i
]->conf_file
, p
[i
]->line
);
448 if (p
[i
]->level
[n
] == 0) {
459 p
= ngx_array_push(&cf
->cycle
->pathes
);
471 ngx_create_pathes(ngx_cycle_t
*cycle
, ngx_uid_t user
)
477 path
= cycle
->pathes
.elts
;
478 for (i
= 0; i
< cycle
->pathes
.nelts
; i
++) {
480 if (ngx_create_dir(path
[i
]->name
.data
, 0700) == NGX_FILE_ERROR
) {
482 if (err
!= NGX_EEXIST
) {
483 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, err
,
484 ngx_create_dir_n
" \"%s\" failed",
490 if (user
== (ngx_uid_t
) NGX_CONF_UNSET_UINT
) {
498 if (ngx_file_info((const char *) path
[i
]->name
.data
, &fi
)
501 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
502 ngx_file_info_n
" \"%s\" failed", path
[i
]->name
.data
);
506 if (fi
.st_uid
!= user
) {
507 if (chown((const char *) path
[i
]->name
.data
, user
, -1) == -1) {
508 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
509 "chown(\"%s\", %d) failed",
510 path
[i
]->name
.data
, user
);
515 if ((fi
.st_mode
& (S_IRUSR
|S_IWUSR
|S_IXUSR
))
516 != (S_IRUSR
|S_IWUSR
|S_IXUSR
))
518 fi
.st_mode
|= (S_IRUSR
|S_IWUSR
|S_IXUSR
);
520 if (chmod((const char *) path
[i
]->name
.data
, fi
.st_mode
) == -1) {
521 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
522 "chmod() \"%s\" failed", path
[i
]->name
.data
);
535 ngx_ext_rename_file(ngx_str_t
*src
, ngx_str_t
*to
, ngx_ext_rename_file_t
*ext
)
544 if (ngx_change_file_access(src
->data
, ext
->access
) == NGX_FILE_ERROR
) {
545 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
546 ngx_change_file_access_n
" \"%s\" failed", src
->data
);
554 if (ext
->time
!= -1) {
555 if (ngx_set_file_time(src
->data
, ext
->fd
, ext
->time
) != NGX_OK
) {
556 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
557 ngx_set_file_time_n
" \"%s\" failed", src
->data
);
563 if (ngx_rename_file(src
->data
, to
->data
) != NGX_FILE_ERROR
) {
569 if (err
== NGX_ENOPATH
) {
571 if (!ext
->create_path
) {
575 err
= ngx_create_full_path(to
->data
, ngx_dir_access(ext
->path_access
));
578 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, err
,
579 ngx_create_dir_n
" \"%s\" failed", to
->data
);
584 if (ngx_rename_file(src
->data
, to
->data
) != NGX_FILE_ERROR
) {
593 if (err
== NGX_EEXIST
) {
594 err
= ngx_win32_rename_file(src
, to
, ext
->log
);
603 if (err
== NGX_EXDEV
) {
607 cf
.access
= ext
->access
;
611 name
= ngx_alloc(to
->len
+ 1 + 10 + 1, ext
->log
);
616 (void) ngx_sprintf(name
, "%*s.%010uD%Z", to
->len
, to
->data
,
617 (uint32_t) ngx_next_temp_number(0));
619 if (ngx_copy_file(src
->data
, name
, &cf
) == NGX_OK
) {
621 if (ngx_rename_file(name
, to
->data
) != NGX_FILE_ERROR
) {
624 if (ngx_delete_file(src
->data
) == NGX_FILE_ERROR
) {
625 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
626 ngx_delete_file_n
" \"%s\" failed",
634 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
635 ngx_rename_file_n
" \"%s\" to \"%s\" failed",
638 if (ngx_delete_file(name
) == NGX_FILE_ERROR
) {
639 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
640 ngx_delete_file_n
" \"%s\" failed", name
);
652 if (ext
->delete_file
) {
653 if (ngx_delete_file(src
->data
) == NGX_FILE_ERROR
) {
654 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
655 ngx_delete_file_n
" \"%s\" failed", src
->data
);
660 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, err
,
661 ngx_rename_file_n
" \"%s\" to \"%s\" failed",
662 src
->data
, to
->data
);
670 ngx_copy_file(u_char
*from
, u_char
*to
, ngx_copy_file_t
*cf
)
682 nfd
= NGX_INVALID_FILE
;
684 fd
= ngx_open_file(from
, NGX_FILE_RDONLY
, NGX_FILE_OPEN
, 0);
686 if (fd
== NGX_INVALID_FILE
) {
687 ngx_log_error(NGX_LOG_CRIT
, cf
->log
, ngx_errno
,
688 ngx_open_file_n
" \"%s\" failed", from
);
692 if (cf
->size
!= -1) {
696 if (ngx_fd_info(fd
, &fi
) == NGX_FILE_ERROR
) {
697 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
698 ngx_fd_info_n
" \"%s\" failed", from
);
703 size
= ngx_file_size(&fi
);
706 len
= cf
->buf_size
? cf
->buf_size
: 65536;
708 if ((off_t
) len
> size
) {
712 buf
= ngx_alloc(len
, cf
->log
);
717 nfd
= ngx_open_file(to
, NGX_FILE_WRONLY
, NGX_FILE_CREATE_OR_OPEN
,
720 if (nfd
== NGX_INVALID_FILE
) {
721 ngx_log_error(NGX_LOG_CRIT
, cf
->log
, ngx_errno
,
722 ngx_open_file_n
" \"%s\" failed", to
);
728 if ((off_t
) len
> size
) {
732 n
= ngx_read_fd(fd
, buf
, len
);
734 if (n
== NGX_FILE_ERROR
) {
735 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
736 ngx_read_fd_n
" \"%s\" failed", from
);
740 if ((size_t) n
!= len
) {
741 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
742 ngx_read_fd_n
" has read only %z of %uz from %s",
747 n
= ngx_write_fd(nfd
, buf
, len
);
749 if (n
== NGX_FILE_ERROR
) {
750 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
751 ngx_write_fd_n
" \"%s\" failed", to
);
755 if ((size_t) n
!= len
) {
756 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
757 ngx_write_fd_n
" has written only %z of %uz to %s",
765 if (ngx_set_file_time(to
, nfd
, cf
->time
) != NGX_OK
) {
766 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
767 ngx_set_file_time_n
" \"%s\" failed", to
);
775 if (nfd
!= NGX_INVALID_FILE
) {
776 if (ngx_close_file(nfd
) == NGX_FILE_ERROR
) {
777 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
778 ngx_close_file_n
" \"%s\" failed", to
);
782 if (fd
!= NGX_INVALID_FILE
) {
783 if (ngx_close_file(fd
) == NGX_FILE_ERROR
) {
784 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
785 ngx_close_file_n
" \"%s\" failed", from
);
798 * ctx->init_handler() - see ctx->alloc
799 * ctx->file_handler() - file handler
800 * ctx->pre_tree_handler() - handler is called before entering directory
801 * ctx->post_tree_handler() - handler is called after leaving directory
802 * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
804 * ctx->data - some data structure, it may be the same on all levels, or
805 * reallocated if ctx->alloc is nonzero
807 * ctx->alloc - a size of data structure that is allocated at every level
808 * and is initilialized by ctx->init_handler()
812 * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
816 ngx_walk_tree(ngx_tree_ctx_t
*ctx
, ngx_str_t
*tree
)
829 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
830 "walk tree \"%V\"", tree
);
832 if (ngx_open_dir(tree
, &dir
) == NGX_ERROR
) {
833 ngx_log_error(NGX_LOG_CRIT
, ctx
->log
, ngx_errno
,
834 ngx_open_dir_n
" \"%s\" failed", tree
->data
);
841 data
= ngx_alloc(ctx
->alloc
, ctx
->log
);
846 if (ctx
->init_handler(data
, prev
) == NGX_ABORT
) {
860 if (ngx_read_dir(&dir
) == NGX_ERROR
) {
863 if (err
== NGX_ENOMOREFILES
) {
867 ngx_log_error(NGX_LOG_CRIT
, ctx
->log
, err
,
868 ngx_read_dir_n
" \"%s\" failed", tree
->data
);
875 len
= ngx_de_namelen(&dir
);
876 name
= ngx_de_name(&dir
);
878 ngx_log_debug2(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
879 "tree name %uz:\"%s\"", len
, name
);
881 if (len
== 1 && name
[0] == '.') {
885 if (len
== 2 && name
[0] == '.' && name
[1] == '.') {
889 file
.len
= tree
->len
+ 1 + len
;
891 if (file
.len
+ NGX_DIR_MASK_LEN
> buf
.len
) {
897 buf
.len
= tree
->len
+ 1 + len
+ NGX_DIR_MASK_LEN
;
899 buf
.data
= ngx_alloc(buf
.len
+ 1, ctx
->log
);
900 if (buf
.data
== NULL
) {
905 p
= ngx_cpymem(buf
.data
, tree
->data
, tree
->len
);
907 ngx_memcpy(p
, name
, len
+ 1);
909 file
.data
= buf
.data
;
911 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
912 "tree path \"%s\"", file
.data
);
914 if (!dir
.valid_info
) {
915 if (ngx_de_info(file
.data
, &dir
) == NGX_FILE_ERROR
) {
916 ngx_log_error(NGX_LOG_CRIT
, ctx
->log
, ngx_errno
,
917 ngx_de_info_n
" \"%s\" failed", file
.data
);
922 if (ngx_de_is_file(&dir
)) {
924 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
925 "tree file \"%s\"", file
.data
);
927 ctx
->size
= ngx_de_size(&dir
);
928 ctx
->access
= ngx_de_access(&dir
);
929 ctx
->mtime
= ngx_de_mtime(&dir
);
931 if (ctx
->file_handler(ctx
, &file
) == NGX_ABORT
) {
935 } else if (ngx_de_is_dir(&dir
)) {
937 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
938 "tree enter dir \"%s\"", file
.data
);
940 ctx
->access
= ngx_de_access(&dir
);
941 ctx
->mtime
= ngx_de_mtime(&dir
);
943 if (ctx
->pre_tree_handler(ctx
, &file
) == NGX_ABORT
) {
947 if (ngx_walk_tree(ctx
, &file
) == NGX_ABORT
) {
951 ctx
->access
= ngx_de_access(&dir
);
952 ctx
->mtime
= ngx_de_mtime(&dir
);
954 if (ctx
->post_tree_handler(ctx
, &file
) == NGX_ABORT
) {
960 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
961 "tree special \"%s\"", file
.data
);
963 if (ctx
->spec_handler(ctx
, &file
) == NGX_ABORT
) {
984 if (ngx_close_dir(&dir
) == NGX_ERROR
) {
985 ngx_log_error(NGX_LOG_CRIT
, ctx
->log
, ngx_errno
,
986 ngx_close_dir_n
" \"%s\" failed", tree
->data
);