3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
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;
18 ngx_write_chain_to_temp_file(ngx_temp_file_t
*tf
, ngx_chain_t
*chain
)
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
);
26 if (rc
== NGX_ERROR
|| rc
== NGX_AGAIN
) {
31 ngx_log_error(tf
->log_level
, tf
->file
.log
, 0, "%s %V",
32 tf
->warn
, &tf
->file
.name
);
36 return ngx_write_chain_to_file(&tf
->file
, chain
, tf
->offset
, tf
->pool
);
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
)
46 ngx_pool_cleanup_t
*cln
;
47 ngx_pool_cleanup_file_t
*clnf
;
49 file
->name
.len
= path
->name
.len
+ 1 + path
->len
+ 10;
51 file
->name
.data
= ngx_pnalloc(pool
, file
->name
.len
+ 1);
52 if (file
->name
.data
== NULL
) {
57 for (i
= 0; i
< file
->name
.len
; i
++) {
58 file
->name
.data
[i
] = 'X';
62 ngx_memcpy(file
->name
.data
, path
->name
.data
, path
->name
.len
);
64 n
= (uint32_t) ngx_next_temp_number(0);
66 cln
= ngx_pool_cleanup_add(pool
, sizeof(ngx_pool_cleanup_file_t
));
72 (void) ngx_sprintf(file
->name
.data
+ path
->name
.len
+ 1 + path
->len
,
75 ngx_create_hashed_filename(path
, file
->name
.data
, file
->name
.len
);
77 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, file
->log
, 0,
78 "hashed path: %s", file
->name
.data
);
80 file
->fd
= ngx_open_tempfile(file
->name
.data
, persistent
, access
);
82 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, file
->log
, 0,
83 "temp fd:%d", file
->fd
);
85 if (file
->fd
!= NGX_INVALID_FILE
) {
87 cln
->handler
= clean
? ngx_pool_delete_file
: ngx_pool_cleanup_file
;
91 clnf
->name
= file
->name
.data
;
92 clnf
->log
= pool
->log
;
99 if (err
== NGX_EEXIST
) {
100 n
= (uint32_t) ngx_next_temp_number(1);
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",
111 if (ngx_create_path(file
, path
) == NGX_ERROR
) {
119 ngx_create_hashed_filename(ngx_path_t
*path
, u_char
*file
, size_t len
)
124 i
= path
->name
.len
+ 1;
126 file
[path
->name
.len
+ path
->len
] = '/';
128 for (n
= 0; n
< 3; n
++) {
129 level
= path
->level
[n
];
137 ngx_memcpy(&file
[i
], &file
[len
], level
);
144 ngx_create_path(ngx_file_t
*file
, ngx_path_t
*path
)
150 pos
= path
->name
.len
;
152 for (i
= 0; i
< 3; i
++) {
153 if (path
->level
[i
] == 0) {
157 pos
+= path
->level
[i
] + 1;
159 file
->name
.data
[pos
] = '\0';
161 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, file
->log
, 0,
162 "temp file: \"%s\"", file
->name
.data
);
164 if (ngx_create_dir(file
->name
.data
, 0700) == NGX_FILE_ERROR
) {
166 if (err
!= NGX_EEXIST
) {
167 ngx_log_error(NGX_LOG_CRIT
, file
->log
, err
,
168 ngx_create_dir_n
" \"%s\" failed",
174 file
->name
.data
[pos
] = '/';
182 ngx_create_full_path(u_char
*dir
, ngx_uint_t access
)
195 for ( /* void */ ; *p
; p
++) {
204 if (ngx_create_dir(dir
, access
) == NGX_FILE_ERROR
) {
226 ngx_next_temp_number(ngx_uint_t collision
)
228 ngx_atomic_uint_t n
, add
;
230 add
= collision
? ngx_random_number
: 1;
232 n
= ngx_atomic_fetch_add(ngx_temp_number
, add
);
239 ngx_conf_set_path_slot(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
246 ngx_path_t
*path
, **slot
;
248 slot
= (ngx_path_t
**) (p
+ cmd
->offset
);
251 return "is duplicate";
254 path
= ngx_pcalloc(cf
->pool
, sizeof(ngx_path_t
));
256 return NGX_CONF_ERROR
;
259 value
= cf
->args
->elts
;
261 path
->name
= value
[1];
263 if (path
->name
.data
[path
->name
.len
- 1] == '/') {
267 if (ngx_conf_full_name(cf
->cycle
, &path
->name
, 0) != NGX_OK
) {
272 path
->manager
= NULL
;
274 path
->conf_file
= cf
->conf_file
->file
.name
.data
;
275 path
->line
= cf
->conf_file
->line
;
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";
283 path
->level
[i
] = level
;
284 path
->len
+= level
+ 1;
288 path
->level
[i
++] = 0;
293 if (ngx_add_path(cf
, slot
) == NGX_ERROR
) {
294 return NGX_CONF_ERROR
;
302 ngx_conf_merge_path_value(ngx_conf_t
*cf
, ngx_path_t
**path
, ngx_path_t
*prev
,
303 ngx_path_init_t
*init
)
314 *path
= ngx_palloc(cf
->pool
, sizeof(ngx_path_t
));
316 return NGX_CONF_ERROR
;
319 (*path
)->name
= init
->name
;
321 if (ngx_conf_full_name(cf
->cycle
, &(*path
)->name
, 0) != NGX_OK
) {
322 return NGX_CONF_ERROR
;
325 (*path
)->level
[0] = init
->level
[0];
326 (*path
)->level
[1] = init
->level
[1];
327 (*path
)->level
[2] = init
->level
[2];
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);
333 (*path
)->manager
= NULL
;
334 (*path
)->loader
= NULL
;
335 (*path
)->conf_file
= NULL
;
337 if (ngx_add_path(cf
, path
) != NGX_OK
) {
338 return NGX_CONF_ERROR
;
346 ngx_conf_set_access_slot(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
352 ngx_uint_t i
, right
, shift
, *access
;
354 access
= (ngx_uint_t
*) (confp
+ cmd
->offset
);
356 if (*access
!= NGX_CONF_UNSET_UINT
) {
357 return "is duplicate";
360 value
= cf
->args
->elts
;
364 for (i
= 1; i
< cf
->args
->nelts
; i
++) {
368 if (ngx_strncmp(p
, "user:", sizeof("user:") - 1) == 0) {
370 p
+= sizeof("user:") - 1;
372 } else if (ngx_strncmp(p
, "group:", sizeof("group:") - 1) == 0) {
374 p
+= sizeof("group:") - 1;
376 } else if (ngx_strncmp(p
, "all:", sizeof("all:") - 1) == 0) {
378 p
+= sizeof("all:") - 1;
384 if (ngx_strcmp(p
, "rw") == 0) {
387 } else if (ngx_strcmp(p
, "r") == 0) {
394 *access
|= right
<< shift
;
401 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0, "invalid value \"%V\"", &value
[i
]);
403 return NGX_CONF_ERROR
;
408 ngx_add_path(ngx_conf_t
*cf
, ngx_path_t
**slot
)
411 ngx_path_t
*path
, **p
;
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)
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",
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
);
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
);
449 if (p
[i
]->level
[n
] == 0) {
460 p
= ngx_array_push(&cf
->cycle
->paths
);
472 ngx_create_paths(ngx_cycle_t
*cycle
, ngx_uid_t user
)
478 path
= cycle
->paths
.elts
;
479 for (i
= 0; i
< cycle
->paths
.nelts
; i
++) {
481 if (ngx_create_dir(path
[i
]->name
.data
, 0700) == NGX_FILE_ERROR
) {
483 if (err
!= NGX_EEXIST
) {
484 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, err
,
485 ngx_create_dir_n
" \"%s\" failed",
491 if (user
== (ngx_uid_t
) NGX_CONF_UNSET_UINT
) {
499 if (ngx_file_info((const char *) path
[i
]->name
.data
, &fi
)
502 ngx_log_error(NGX_LOG_EMERG
, cycle
->log
, ngx_errno
,
503 ngx_file_info_n
" \"%s\" failed", path
[i
]->name
.data
);
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
);
516 if ((fi
.st_mode
& (S_IRUSR
|S_IWUSR
|S_IXUSR
))
517 != (S_IRUSR
|S_IWUSR
|S_IXUSR
))
519 fi
.st_mode
|= (S_IRUSR
|S_IWUSR
|S_IXUSR
);
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
);
536 ngx_ext_rename_file(ngx_str_t
*src
, ngx_str_t
*to
, ngx_ext_rename_file_t
*ext
)
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
);
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
);
564 if (ngx_rename_file(src
->data
, to
->data
) != NGX_FILE_ERROR
) {
570 if (err
== NGX_ENOPATH
) {
572 if (!ext
->create_path
) {
576 err
= ngx_create_full_path(to
->data
, ngx_dir_access(ext
->path_access
));
579 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, err
,
580 ngx_create_dir_n
" \"%s\" failed", to
->data
);
585 if (ngx_rename_file(src
->data
, to
->data
) != NGX_FILE_ERROR
) {
594 if (err
== NGX_EEXIST
) {
595 err
= ngx_win32_rename_file(src
, to
, ext
->log
);
604 if (err
== NGX_EXDEV
) {
608 cf
.access
= ext
->access
;
612 name
= ngx_alloc(to
->len
+ 1 + 10 + 1, ext
->log
);
617 (void) ngx_sprintf(name
, "%*s.%010uD%Z", to
->len
, to
->data
,
618 (uint32_t) ngx_next_temp_number(0));
620 if (ngx_copy_file(src
->data
, name
, &cf
) == NGX_OK
) {
622 if (ngx_rename_file(name
, to
->data
) != NGX_FILE_ERROR
) {
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",
635 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, ngx_errno
,
636 ngx_rename_file_n
" \"%s\" to \"%s\" failed",
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
);
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
);
661 ngx_log_error(NGX_LOG_CRIT
, ext
->log
, err
,
662 ngx_rename_file_n
" \"%s\" to \"%s\" failed",
663 src
->data
, to
->data
);
671 ngx_copy_file(u_char
*from
, u_char
*to
, ngx_copy_file_t
*cf
)
683 nfd
= NGX_INVALID_FILE
;
685 fd
= ngx_open_file(from
, NGX_FILE_RDONLY
, NGX_FILE_OPEN
, 0);
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
);
693 if (cf
->size
!= -1) {
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
);
704 size
= ngx_file_size(&fi
);
707 len
= cf
->buf_size
? cf
->buf_size
: 65536;
709 if ((off_t
) len
> size
) {
713 buf
= ngx_alloc(len
, cf
->log
);
718 nfd
= ngx_open_file(to
, NGX_FILE_WRONLY
, NGX_FILE_CREATE_OR_OPEN
,
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
);
729 if ((off_t
) len
> size
) {
733 n
= ngx_read_fd(fd
, buf
, len
);
736 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
737 ngx_read_fd_n
" \"%s\" failed", from
);
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",
748 n
= ngx_write_fd(nfd
, buf
, len
);
751 ngx_log_error(NGX_LOG_ALERT
, cf
->log
, ngx_errno
,
752 ngx_write_fd_n
" \"%s\" failed", to
);
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",
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
);
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
);
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
);
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
807 * ctx->data - some data structure, it may be the same on all levels, or
808 * reallocated if ctx->alloc is nonzero
810 * ctx->alloc - a size of data structure that is allocated at every level
811 * and is initialized by ctx->init_handler()
815 * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
819 ngx_walk_tree(ngx_tree_ctx_t
*ctx
, ngx_str_t
*tree
)
831 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
832 "walk tree \"%V\"", tree
);
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
);
843 data
= ngx_alloc(ctx
->alloc
, ctx
->log
);
848 if (ctx
->init_handler(data
, prev
) == NGX_ABORT
) {
862 if (ngx_read_dir(&dir
) == NGX_ERROR
) {
865 if (err
== NGX_ENOMOREFILES
) {
869 ngx_log_error(NGX_LOG_CRIT
, ctx
->log
, err
,
870 ngx_read_dir_n
" \"%s\" failed", tree
->data
);
877 len
= ngx_de_namelen(&dir
);
878 name
= ngx_de_name(&dir
);
880 ngx_log_debug2(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
881 "tree name %uz:\"%s\"", len
, name
);
883 if (len
== 1 && name
[0] == '.') {
887 if (len
== 2 && name
[0] == '.' && name
[1] == '.') {
891 file
.len
= tree
->len
+ 1 + len
;
893 if (file
.len
+ NGX_DIR_MASK_LEN
> buf
.len
) {
899 buf
.len
= tree
->len
+ 1 + len
+ NGX_DIR_MASK_LEN
;
901 buf
.data
= ngx_alloc(buf
.len
+ 1, ctx
->log
);
902 if (buf
.data
== NULL
) {
907 p
= ngx_cpymem(buf
.data
, tree
->data
, tree
->len
);
909 ngx_memcpy(p
, name
, len
+ 1);
911 file
.data
= buf
.data
;
913 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
914 "tree path \"%s\"", file
.data
);
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
);
924 if (ngx_de_is_file(&dir
)) {
926 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
927 "tree file \"%s\"", file
.data
);
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
);
934 if (ctx
->file_handler(ctx
, &file
) == NGX_ABORT
) {
938 } else if (ngx_de_is_dir(&dir
)) {
940 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
941 "tree enter dir \"%s\"", file
.data
);
943 ctx
->access
= ngx_de_access(&dir
);
944 ctx
->mtime
= ngx_de_mtime(&dir
);
946 if (ctx
->pre_tree_handler(ctx
, &file
) == NGX_ABORT
) {
950 if (ngx_walk_tree(ctx
, &file
) == NGX_ABORT
) {
954 ctx
->access
= ngx_de_access(&dir
);
955 ctx
->mtime
= ngx_de_mtime(&dir
);
957 if (ctx
->post_tree_handler(ctx
, &file
) == NGX_ABORT
) {
963 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, ctx
->log
, 0,
964 "tree special \"%s\"", file
.data
);
966 if (ctx
->spec_handler(ctx
, &file
) == NGX_ABORT
) {
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
);