# HG changeset patch # User Igor Sysoev # Date 1167050280 0 # Node ID 8c3d62474df180b3749a3bcf028f643bb897c93a # Parent ff762576da78a50e4e0dfceb781414564d83730b ngx_walk_tree() diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -418,3 +418,168 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng return NGX_OK; } + + +ngx_int_t +ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) +{ + void *data, *prev; + u_char *p, *name; + size_t len; + ngx_int_t rc; + ngx_err_t err; + ngx_str_t file, buf; + ngx_dir_t dir; + + buf.len = 0; + buf.data = NULL; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "walk tree \"%V\"", tree); + + if (ngx_open_dir(tree, &dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_open_dir_n " \"%s\" failed", tree->data); + return NGX_ERROR; + } + + prev = ctx->data; + + if (ctx->size) { + data = ngx_alloc(ctx->size, ctx->log); + if (data == NULL) { + goto failed; + } + + if (ctx->init_handler(data, prev) == NGX_ABORT) { + goto failed; + } + + ctx->data = data; + } + + for ( ;; ) { + + ngx_set_errno(0); + + if (ngx_read_dir(&dir) == NGX_ERROR) { + err = ngx_errno; + + if (err == NGX_ENOMOREFILES) { + rc = NGX_OK; + + } else { + ngx_log_error(NGX_LOG_CRIT, ctx->log, err, + ngx_read_dir_n " \"%s\" failed", tree->data); + rc = NGX_ERROR; + } + + goto done; + } + + len = ngx_de_namelen(&dir); + name = ngx_de_name(&dir); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree name %uz:\"%s\"", len, name); + + if (len == 1 && name[0] == '.') { + continue; + } + + if (len == 2 && name[0] == '.' && name[1] == '.') { + continue; + } + + file.len = tree->len + 1 + len; + + if (file.len + NGX_DIR_MASK_LEN > buf.len) { + + if (buf.len) { + ngx_free(buf.data); + } + + buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN; + + buf.data = ngx_alloc(buf.len + 1, ctx->log); + if (buf.data == NULL) { + goto failed; + } + } + + p = ngx_cpymem(buf.data, tree->data, tree->len); + *p++ = '/'; + ngx_memcpy(p, name, len + 1); + + file.data = buf.data; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree path \"%s\"", file.data); + + if (!dir.valid_info) { + if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_de_info_n " \"%s\" failed", file.data); + continue; + } + } + + if (ngx_de_is_file(&dir)) { + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree file \"%s\"", file.data); + + if (ctx->file_handler(ctx, &file) == NGX_ABORT) { + goto failed; + } + + } else if (ngx_de_is_dir(&dir)) { + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree enter dir \"%s\"", file.data); + + if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) { + goto failed; + } + + if (ngx_walk_tree(ctx, &file) == NGX_ABORT) { + goto failed; + } + + if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) { + goto failed; + } + + } else { + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree special \"%s\"", file.data); + + if (ctx->spec_handler(ctx, &file) == NGX_ABORT) { + goto failed; + } + } + } + +failed: + + rc = NGX_ABORT; + +done: + + if (buf.len) { + ngx_free(buf.data); + } + + if (ctx->data) { + ngx_free(ctx->data); + ctx->data = prev; + } + + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_close_dir_n " \"%s\" failed", tree->data); + } + + return rc; +} diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -56,6 +56,24 @@ typedef struct { } ngx_temp_file_t; +typedef struct ngx_tree_ctx_s ngx_tree_ctx_t; + +typedef ngx_int_t (*ngx_tree_init_handler_pt) (ngx_tree_ctx_t *ctx, + ngx_tree_ctx_t *prev); +typedef ngx_int_t (*ngx_tree_handler_pt) (ngx_tree_ctx_t *ctx, ngx_str_t *name); + +struct ngx_tree_ctx_s { + ngx_tree_init_handler_pt init_handler; + ngx_tree_handler_pt file_handler; + ngx_tree_handler_pt pre_tree_handler; + ngx_tree_handler_pt post_tree_handler; + ngx_tree_handler_pt spec_handler; + void *data; + size_t size; + ngx_log_t *log; +}; + + ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain); ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t mode); @@ -64,6 +82,7 @@ ngx_int_t ngx_create_path(ngx_file_t *fi ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access); ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot); ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); +ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree); void ngx_init_temp_number(void); ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);