static ngx_int_t
ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
    ngx_file_info_t *fi, ngx_log_t *log)
{
    ngx_int_t  rc;

#if !(NGX_HAVE_OPENAT)

    rc = ngx_file_info(name->data, fi);

    if (rc == NGX_FILE_ERROR) {
        of->err = ngx_errno;
        of->failed = ngx_file_info_n;
        return NGX_FILE_ERROR;
    }

    return rc;

#else

    ngx_fd_t  fd;

    if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {

        rc = ngx_file_info(name->data, fi);

        if (rc == NGX_FILE_ERROR) {
            of->err = ngx_errno;
            of->failed = ngx_file_info_n;
            return NGX_FILE_ERROR;
        }

        return rc;
    }

    fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
                               NGX_FILE_OPEN, 0, log);

    if (fd == NGX_INVALID_FILE) {
        return NGX_FILE_ERROR;
    }

    rc = ngx_fd_info(fd, fi);

    if (rc == NGX_FILE_ERROR) {
        of->err = ngx_errno;
        of->failed = ngx_fd_info_n;
    }

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                      ngx_close_file_n " \"%V\" failed", name);
    }

    return rc;
#endif
}
static char *
ngx_http_pi_module_command(ngx_conf_t *cf, 
    ngx_command_t *cmd, void *conf)
{
    ngx_int_t                      rc;
    ngx_err_t                      err;
    ngx_http_core_loc_conf_t      *clcf;
    ngx_http_pi_loc_conf_t        *plcf;
    ngx_str_t                     *value;
    ngx_file_t                     file;
    ngx_file_info_t                fi;

    plcf = conf;
    value = cf->args->elts;

    ngx_memzero(&file, sizeof(ngx_file_t));
    file.name = value[1];
    file.log = cf->log;

    file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0);
    if (file.fd == NGX_INVALID_FILE) {
        err = ngx_errno;
        if (err != NGX_ENOENT) {
            ngx_conf_log_error(NGX_LOG_CRIT, cf, err,
                               ngx_open_file_n " \"%s\" failed", file.name.data);
        }
        return NGX_CONF_ERROR;
    }

    if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
        ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
                           ngx_fd_info_n " \"%s\" failed", file.name.data);
        rc = NGX_ERROR;

        goto done;
    }

    plcf->size = (size_t) ngx_file_size(&fi);

    plcf->buf = mmap(NULL, plcf->size, PROT_READ, MAP_SHARED, file.fd, 0);

    rc = NGX_OK;

done:

    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                      ngx_close_file_n " \"%s\" failed", file.name.data);
    }

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_pi_handler;

    return rc == NGX_OK ? NGX_CONF_OK : NGX_CONF_ERROR;
}
static int
ngx_squ_file_index(squ_State *l)
{
    ngx_str_t            key;
    ngx_file_info_t      fi;
    ngx_http_request_t  *r;
    ngx_squ_file_ctx_t  *ctx;

    thr = ngx_squ_thread(l);

    ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->connection->log, 0, "squ file index");

    key.data = (u_char *) squL_checklstring(l, -1, &key.len);

    switch (key.len) {

    case 4:

        if (ngx_strncmp(key.data, "size", 4) == 0) {
            ctx = ngx_squ_file(l);

            ngx_memzero(&fi, sizeof(ngx_file_info_t));

            if (ngx_fd_info(ctx->file.fd, &fi) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                              ngx_fd_info_n " failed");
                squ_pushnil(l);
                squ_pushstring(l, ngx_fd_info_n " failed");
                return 1;
            }

            squ_pushnumber(l, (squ_Number) ngx_file_size(&fi));

            return 1;
        }

        break;

    case 10:

        if (ngx_strncmp(key.data, "attributes", 10) == 0) {
            /* TODO */
        }

        break;

    default:
        break;
    }

    return 0;
}
static ngx_int_t
ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log)
{
    static ngx_uint_t  use_fstat = 1;

    /*
     * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain
     * a descriptor without actually opening file or directory.  It requires
     * less permissions for path components, but till Linux 3.6 fstat() returns
     * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag
     * should be used instead.
     *
     * Three scenarios are handled in this function:
     *
     * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was
     *    backported by vendor.  Then fstat() is used.
     *
     * 2) The kernel is newer than 2.6.39 but older than 3.6.  In this case
     *    the first call of fstat() returns EBADF and we fallback to fstatat()
     *    with AT_EMPTY_PATH which was introduced at the same time as O_PATH.
     *
     * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH
     *    support.  Since descriptors are opened with O_PATH|O_RDONLY flags
     *    and O_PATH is ignored by the kernel then the O_RDONLY flag is
     *    actually used.  In this case fstat() just works.
     */

    if (use_fstat) {
        if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) {
            return NGX_OK;
        }

        if (ngx_errno != NGX_EBADF) {
            return NGX_ERROR;
        }

        ngx_log_error(NGX_LOG_NOTICE, log, 0,
                      "fstat(O_PATH) failed with EBADF, "
                      "switching to fstatat(AT_EMPTY_PATH)");

        use_fstat = 0;
    }

    if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) {
        return NGX_OK;
    }

    return NGX_ERROR;
}
ngx_int_t ngx_http_small_light_imlib2_process(ngx_http_request_t *r, ngx_http_small_light_ctx_t *ctx)
{
    ngx_http_small_light_imlib2_ctx_t *ictx;
    ngx_http_small_light_image_size_t sz;
    Imlib_Image image_org, image_dst, image_tmp;
    Imlib_Load_Error err;
    ngx_file_info_t fi;
    ngx_fd_t fd;
    char *filename, *sharpen, *blur, *of, *buf;
    void *data;
    int w, h, radius, orientation;
    double iw, ih, q;
    ngx_int_t type;
    const char *ext;
    ssize_t size;

    ictx = (ngx_http_small_light_imlib2_ctx_t *)ctx->ictx;

    filename = (char *)ictx->tf->file.name.data;

    /* adjust image size */
    ngx_http_small_light_calc_image_size(r, ctx, &sz, 10000.0, 10000.0);

    if (sz.jpeghint_flg != 0) {
        if (ngx_http_small_light_load_jpeg((void**)&data, &w, &h, r, filename, sz.dw, sz.dh) != NGX_OK) {
            image_org = imlib_load_image_immediately_without_cache(filename);
            if (image_org == NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "failed to load image %s:%d",
                              __FUNCTION__,
                              __LINE__);
                return NGX_ERROR;
            }
        } else {
            image_org = imlib_create_image_using_data(w, h, data);
        }
    } else {
        image_org = imlib_load_image_immediately_without_cache(filename);
        if (image_org == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "failed to load image %s:%d",
                          __FUNCTION__,
                          __LINE__);
            return NGX_ERROR;
        }
    }

    /* rotate. */
    if (sz.angle) {
        orientation = 0;
        switch (sz.angle) {
        case 90:
            orientation = 1;
            break;
        case 180:
            orientation = 2;
            break;
        case 270:
            orientation = 3;
            break;
        default:
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "image not rotated. 'angle'(%d) must be 90 or 180 or 270. %s:%d",
                          sz.angle,
                          __FUNCTION__,
                          __LINE__);
            break;
        }

        imlib_context_set_image(image_org);
        imlib_image_orientate(orientation);
    }

    /* calc size. */
    imlib_context_set_image(image_org);
    iw = (double)imlib_image_get_width();
    ih = (double)imlib_image_get_height();
    ngx_http_small_light_calc_image_size(r, ctx, &sz, iw, ih);

    /* pass through. */
    if (sz.pt_flg != 0) {
        ctx->of = ctx->inf;
        return NGX_OK;
    }

    /* crop, scale. */
    if (sz.scale_flg != 0) {
        image_dst = imlib_create_cropped_scaled_image((int)sz.sx, (int)sz.sy, (int)sz.sw, (int)sz.sh, (int)sz.dw, (int)sz.dh);
        imlib_context_set_image(image_org);
        imlib_free_image();
    } else {
        image_dst = image_org;
    }

    if (image_dst == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "imlib_create_cropped_scaled_image failed. %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    /* create canvas then draw image to the canvas. */
    if (sz.cw > 0.0 && sz.ch > 0.0) {
        image_tmp = imlib_create_image(sz.cw, sz.ch);
        if (image_tmp == NULL) {
            imlib_context_set_image(image_dst);
            imlib_free_image();
            return NGX_ERROR;
        }
        imlib_context_set_image(image_tmp);
        imlib_context_set_color(sz.cc.r, sz.cc.g, sz.cc.b, sz.cc.a);
        imlib_image_fill_rectangle(0, 0, sz.cw, sz.ch);
        imlib_blend_image_onto_image(image_dst, 255, 0, 0,
                                     (int)sz.dw, (int)sz.dh, (int)sz.dx, (int)sz.dy, (int)sz.dw, (int)sz.dh);
        imlib_context_set_image(image_dst);
        imlib_free_image();
        image_dst = image_tmp;
    }

    /* effects. */
    sharpen = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "sharpen");
    if (sharpen) {
        radius = ngx_http_small_light_parse_int(sharpen);
        if (radius > 0) {
            imlib_context_set_image(image_dst);
            imlib_image_sharpen(radius);
        }
    }

    blur = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "blur");
    if (blur) {
        radius = ngx_http_small_light_parse_int(blur);
        if (radius > 0) {
            imlib_context_set_image(image_dst);
            imlib_image_blur(radius);
        }
    }

    /* border. */
    if (sz.bw > 0.0 || sz.bh > 0.0) {
        imlib_context_set_color(sz.bc.r, sz.bc.g, sz.bc.b, sz.bc.a);
        imlib_context_set_image(image_dst);
        if (sz.cw > 0.0 && sz.ch > 0.0) {
            imlib_image_fill_rectangle(0, 0, sz.cw, sz.bh);
            imlib_image_fill_rectangle(0, 0, sz.bw, sz.ch);
            imlib_image_fill_rectangle(0, sz.ch - sz.bh, sz.cw, sz.bh);
            imlib_image_fill_rectangle(sz.cw - sz.bw, 0, sz.bw, sz.ch);
        } else {
            imlib_image_fill_rectangle(0, 0, sz.dw, sz.bh);
            imlib_image_fill_rectangle(0, 0, sz.bw, sz.ch);
            imlib_image_fill_rectangle(0, sz.dh - sz.bh, sz.dw, sz.bh);
            imlib_image_fill_rectangle(sz.dw - sz.bw, 0, sz.bw, sz.dh);
        }
    }

    /* set params. */
    imlib_context_set_image(image_dst);
    q = ngx_http_small_light_parse_double(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "q"));
    if (q > 0.0) {
        imlib_image_attach_data_value("quality", NULL, q, NULL);
    }

    of = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "of");
    if (ngx_strlen(of) > 0) {
        type = ngx_http_small_light_type(of);
        if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_NONE) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "of is invalid(%s) %s:%d",
                          of,
                          __FUNCTION__,
                          __LINE__);
            of = (char *)ngx_http_small_light_image_exts[ictx->type - 1];
        } else if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_WEBP) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "WebP is not supported %s:%d",
                          __FUNCTION__,
                          __LINE__);
            of = (char *)ngx_http_small_light_image_exts[ictx->type - 1];
        } else {
            ictx->type = type;
        }
        imlib_image_set_format(of);
        ctx->of = ngx_http_small_light_image_types[ictx->type - 1];
    } else {
        ext = ngx_http_small_light_image_exts[ictx->type - 1];
        imlib_image_set_format(ext);
        ctx->of = ctx->inf;
    }

    /* save image. */
    imlib_save_image_with_error_return(filename, &err);
    imlib_free_image();

    /* check error. */
    if (err != IMLIB_LOAD_ERROR_NONE) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to imlib_save_error %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    if (ngx_file_info(filename, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to ngx_file_info %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    fd = ngx_open_file(filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to open fd %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to ngx_fd_info %s:%d",
                      __FUNCTION__,
                      __LINE__);
        ngx_close_file(fd);
        return NGX_ERROR;
    } 

    buf = ngx_palloc(r->pool, ngx_file_size(&fi));
    if (buf == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to allocate memory from r->pool %s:%d",
                      __FUNCTION__,
                      __LINE__);
        ngx_close_file(fd);
        return NGX_ERROR;
    }
    size = ngx_read_fd(fd, buf, ngx_file_size(&fi));
    if (size == -1) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to ngx_read_fd %s:%d",
                      __FUNCTION__,
                      __LINE__);
        ngx_close_file(fd);
        return NGX_ERROR;
    }

    if ((size_t)size > ctx->content_length) {
        ctx->content = ngx_palloc(r->pool, size);
        if (ctx->content == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "failed to allocate memory from r->pool %s:%d",
                          __FUNCTION__,
                          __LINE__);
            ngx_close_file(fd);
            return NGX_ERROR;
        }
    }

    ngx_memcpy(ctx->content, buf, size);

    ngx_close_file(fd);

    ctx->content_length = size;

    return NGX_OK;
}
//解析filename中的配置项
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf;
    ngx_conf_file_t  *prev, conf_file;
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {

        /* open configuration file */

		//首先打开配置文件
        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

		//令cf->conf_file指向临时的conf_file结构体
        prev = cf->conf_file;

        cf->conf_file = &conf_file;

		//获取配置文件的inode信息
        if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

		//我们将文件读取到cf->conf_file->buffer中
        cf->conf_file->buffer = &buf;

        buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
        if (buf.start == NULL) {
            goto failed;
        }

        buf.pos = buf.start;
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;
        buf.temporary = 1;	//这是一个临时buf

        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        type = parse_file;

    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

        type = parse_block;

    } else {
        type = parse_param;
    }


	//使用状态机方式解析配置项
    for ( ;; ) {
		//读取配置文件并解析, 每次返回NGX_OK,说明已经解析到一条配置项,
		//我们会调用响应的回调函数进行处理
		rc = ngx_conf_read_token(cf);

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        if (rc == NGX_CONF_BLOCK_DONE) {

            if (type != parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_FILE_DONE) {

            if (type == parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "unexpected end of file, expecting \"}\"");
                goto failed;
            }

            goto done;
        }

		//如果碰到当前配置块的开始,则我们继续,否则返回失败
        if (rc == NGX_CONF_BLOCK_START) {

            if (type == parse_param) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "block directives are not supported "
                                   "in -g option");
                goto failed;
            }
        }

        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

		//在解析到配置项以后,如果自定义了handler函数则调用handler函数,
		//否则调用默认的set方法设置参数
        if (cf->handler) {

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }


		//调用cf->set方法设置配置项,一次只能设置一个配置项,当出现子模块时
		//set方法会递归解析子模块,并进行配置
        rc = ngx_conf_handler(cf, rc);

        if (rc == NGX_ERROR) {
            goto failed;
        }
    }

failed:

    rc = NGX_ERROR;

done:

    if (filename) {
        if (cf->conf_file->buffer->start) {
            ngx_free(cf->conf_file->buffer->start);
        }

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          filename->data);
            return NGX_CONF_ERROR;
        }

        cf->conf_file = prev;
    }

    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
void
ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
{
    off_t                   fs_size;
    ngx_int_t               rc;
    ngx_file_uniq_t         uniq;
    ngx_file_info_t         fi;
    ngx_http_cache_t        *c;
    ngx_ext_rename_file_t   ext;
    ngx_http_file_cache_t  *cache;

    c = r->cache;

    if (c->updated) {
        return;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache update");

    c->updated = 1;						//	???
    c->updating = 0;

    cache = c->file_cache;

    uniq = 0;
    fs_size = 0;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache rename: \"%s\" to \"%s\"",
                   tf->file.name.data, c->file.name.data);

    ext.access = NGX_FILE_OWNER_ACCESS;
    ext.path_access = NGX_FILE_OWNER_ACCESS;
    ext.time = -1;								//	不更改文件的修改时间
    ext.create_path = 1;						//	如果目录不存在将创建目录
    ext.delete_file = 1;
    ext.log = r->connection->log;

	//	改变临时文件的名字(c->file.name 在哪里设置的???)
    rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);

    if (rc == NGX_OK) {

		//	获取文件信息
        if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", tf->file.name.data);

            rc = NGX_ERROR;

        } else {
            uniq = ngx_file_uniq(&fi);		//	文件结点号

            fs_size = (ngx_file_fs_size(&fi) + cache->bsize - 1) / cache->bsize;
        }
    }

    ngx_shmtx_lock(&cache->shpool->mutex);

    c->node->count--;
    c->node->uniq = uniq;
    c->node->body_start = c->body_start;

    cache->sh->size += fs_size - c->node->fs_size;
    c->node->fs_size = fs_size;

    if (rc == NGX_OK) {
        c->node->exists = 1;
    }

    c->node->updating = 0;

    ngx_shmtx_unlock(&cache->shpool->mutex);
}
Exemple #8
0
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t        *b;
    ngx_uint_t        block;
    ngx_conf_file_t  *prev;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {

        /* open configuration file */

        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

        prev = cf->conf_file;

        cf->conf_file = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t));
        if (cf->conf_file == NULL) {
            return NGX_CONF_ERROR;
        }

        if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

        b = ngx_calloc_buf(cf->pool);
        if (b == NULL) {
            return NGX_CONF_ERROR;
        }

        cf->conf_file->buffer = b;

        b->start = ngx_alloc(ngx_pagesize, cf->log);
        if (b->start == NULL) {
            return NGX_CONF_ERROR;
        }

        b->pos = b->start;
        b->last = b->start;
        b->end = b->last + ngx_pagesize;
        b->temporary = 1;

        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        block = 0;

    } else {
        block = 1;
    }


    for ( ;; ) {
        rc = ngx_conf_read_token(cf);

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        if (rc == NGX_CONF_BLOCK_DONE) {
            if (!block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            block = 0;
        }

        if (rc == NGX_CONF_FILE_DONE && block) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "unexpected end of file, expecting \"}\"");
            goto failed;
        }

        if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) {
            goto done;
        }

        if (cf->handler) {

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }


        rc = ngx_conf_handler(cf, rc);

        if (rc == NGX_ERROR) {
            goto failed;
        }
    }

failed:

    rc = NGX_ERROR;

done:

    if (filename) {
        ngx_free(cf->conf_file->buffer->start);

        cf->conf_file = prev;

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          cf->conf_file->file.name.data);
            return NGX_CONF_ERROR;
        }
    }

    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
Exemple #9
0
//这个函数的详细解析
//请参看:http://www.pagefault.info/?p=188  nginx的启动流程分析(一)
//			http://www.pagefault.info/?p=368
//第二个参数可以为空的,如果为空,则说明将要解析的是block中的内容或者param
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf;
    ngx_conf_file_t  *prev, conf_file;
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;

// 经过这个宏
#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {

        /* open configuration file */
        // 打开配置文件
        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        // NGX_INVALID_FILE 为宏定义,值为-1 ,定义在/os/unix/ngx_files.h 中
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

        prev = cf->conf_file;

        cf->conf_file = &conf_file;
        // 获取配置文件的stat信息,并存储到cf->conf_file->file.info这个stat结构体中
        // ngx_fd_info 这个函数是fstat这个函数的宏包装。参考./os/unix/ngx_files.h
        if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

        cf->conf_file->buffer = &buf;

        // 申请一个NGX_CONF_BUFFER大小的buffer,用于 ngx_conf_read_token() 函数解析配置文件
        buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
        if (buf.start == NULL) {
            goto failed;
        }

        buf.pos = buf.start;
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;
        buf.temporary = 1;
        // 保存配置文件的基本信息
        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        type = parse_file;

    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

        type = parse_block;

    } else {
        type = parse_param;
    }

    //循环遍历每一行配置文件,读取配置内容
    for ( ;; ) {
		//读入一个token,一般是一行
		//读到的配置参数放到: (ngx_str_t*)(*((*cf).args)).elts
        rc = ngx_conf_read_token(cf);

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        if (rc == NGX_CONF_BLOCK_DONE) {

            if (type != parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_FILE_DONE) {

            if (type == parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "unexpected end of file, expecting \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_BLOCK_START) {

            if (type == parse_param) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "block directives are not supported "
                                   "in -g option");
                goto failed;
            }
        }

        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */
        //判断cf是否有handler回调,如果有的话,优先调用handler回调,如果没有,则会进入ngx_conf_handler进行一般处理
        //特别说一下,http的模块使用handler是ngx_http_block,具体请看ngx_http.c
        if (cf->handler) {

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */
            
            //使用handler处理
            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }

        //否则进入一般处理, 调用ngx_conf_handler对当前的token进行处理
        // 参数中的rc 为ngx_read_conf_token的返回值
        rc = ngx_conf_handler(cf, rc);

        if (rc == NGX_ERROR) {
            goto failed;
        }
    } //end for

failed:

    rc = NGX_ERROR;

done:

    //恢复现存、关闭已经打开的文件
    //NGX_CONF_FILE_DONE 时必须要处理的部分
    if (filename) {
        if (cf->conf_file->buffer->start) {
            ngx_free(cf->conf_file->buffer->start);
        }

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          filename->data);
            return NGX_CONF_ERROR;
        }

        cf->conf_file = prev;
    }

    // NGX_ERROR NGX_CONF_FILE_DONE NGX_CONF_BLOCK_DONE 时都需要处理的部分
    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
{
  u_char                      *last;
  ngx_fd_t                     fd;
  ngx_int_t                    rc;
  ngx_uint_t                   level;
  ngx_str_t                    name, location;
  ngx_err_t                    err;
  ngx_log_t                   *log;
  ngx_buf_t                   *b;
  ngx_chain_t                  out;
  ngx_file_info_t              fi;
  ngx_http_cleanup_t          *file_cleanup, *redirect_cleanup;
  ngx_http_log_ctx_t          *ctx;
  ngx_http_core_loc_conf_t    *clcf;
  ngx_http_static_loc_conf_t  *slcf;
#if (NGX_HTTP_CACHE)
  uint32_t                     file_crc, redirect_crc;
  ngx_http_cache_t            *file, *redirect;
#endif

  if (r->uri.data[r->uri.len - 1] == '/') {
    return NGX_DECLINED;
  }

  if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
    return NGX_HTTP_NOT_ALLOWED;
  }

  rc = ngx_http_discard_body(r);

  if (rc != NGX_OK && rc != NGX_AGAIN) {
    return rc;
  }

#if (NGX_HTTP_CACHE)

  /*
   * there is a valid cached open file, i.e by the index handler,
   * and it should be already registered in r->cleanup
   */

  if (r->cache && !r->cache->expired) {
    return ngx_http_send_cached(r);
  }

#endif

  log = r->connection->log;

  clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  /*
   * make a file name, reserve 2 bytes for a trailing '/'
   * in a possible redirect and for the last '\0'
   */

  if (clcf->alias) {
    name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2
                    - clcf->name.len);
    if (name.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
    last = ngx_cpystrn(last, r->uri.data + clcf->name.len,
               r->uri.len + 1 - clcf->name.len);

    name.len = last - name.data;

    location.data = ngx_palloc(r->pool, r->uri.len + 2);
    if (location.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);

#if 0
    /*
     * aliases usually have trailling "/",
     * set it in the start of the possible redirect
     */

    if (*location.data != '/') {
      location.data--;
    }
#endif

    location.len = last - location.data + 1;

  } else {
    name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
    if (name.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);

    name.len = last - name.data;
    location.len = last - location.data + 1;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
           "http filename: \"%s\"", name.data);


  /* allocate cleanups */

  if (!(file_cleanup = ngx_push_array(&r->cleanup))) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  file_cleanup->valid = 0;

  slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
  if (slcf->redirect_cache) {
    if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    redirect_cleanup->valid = 0;

  } else {
    redirect_cleanup = NULL;
  }

#if (NGX_HTTP_CACHE)

  /* look up an open files cache */

  if (clcf->open_files) {
    file = ngx_http_cache_get(clcf->open_files, file_cleanup,
                  &name, &file_crc);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http open file cache get: " PTR_FMT, file);

    if (file && !file->expired) {
      r->cache = file;
      return ngx_http_send_cached(r);
    }

  } else {
    file = NULL;
  }


  /* look up an redirect cache */

  if (slcf->redirect_cache) {
    redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
                    &name, &redirect_crc);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http redirect cache get: " PTR_FMT, redirect);

    if (redirect && !redirect->expired) {

      /*
       * We do not copy a cached value so the cache entry is locked
       * until the end of the request.  In a single threaded model
       * the redirected request should complete before other event
       * will be processed.  In a multithreaded model this locking
       * should keep more popular redirects in cache.
       */

      if (!(r->headers_out.location =
           ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
      {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }

      r->headers_out.location->value = redirect->data.value;

      return NGX_HTTP_MOVED_PERMANENTLY;
    }

  } else {
    redirect = NULL;
  }

#endif

  /* open file */

#if (WIN9X)

  /* TODO: redirect cache */

  if (ngx_win32_version < NGX_WIN_NT) {

    /*
     * there is no way to open a file or a directory in Win9X with
     * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag
     * so we need to check its type before the opening
     */

    if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) {
      err = ngx_errno;
      ngx_log_error(NGX_LOG_ERR, log, err,
              ngx_file_info_n " \"%s\" failed", name.data);

      if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
        return NGX_HTTP_NOT_FOUND;

      } else if (err == NGX_EACCES) {
        return NGX_HTTP_FORBIDDEN;

      } else {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
    }

    if (ngx_is_dir(&fi)) {
      ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data);

      if (!(r->headers_out.location =
           ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
      {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }

      *last++ = '/';
      *last = '\0';
      r->headers_out.location->value.len = last - location;
      r->headers_out.location->value.data = location;

      return NGX_HTTP_MOVED_PERMANENTLY;
    }
  }

#endif


  fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);

  if (fd == NGX_INVALID_FILE) {
    err = ngx_errno;

    if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
      level = NGX_LOG_ERR;
      rc = NGX_HTTP_NOT_FOUND;

    } else if (err == NGX_EACCES) {
      level = NGX_LOG_ERR;
      rc = NGX_HTTP_FORBIDDEN;

    } else {
      level = NGX_LOG_CRIT;
      rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_log_error(level, log, err,
            ngx_open_file_n " \"%s\" failed", name.data);

    return rc;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);

  if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
    ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
            ngx_fd_info_n " \"%s\" failed", name.data);

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  if (ngx_is_dir(&fi)) {

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    *last++ = '/';
    *last = '\0';

    r->headers_out.location = ngx_list_push(&r->headers_out.headers);
    if (r->headers_out.location == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->headers_out.location->value = location;

#if (NGX_HTTP_CACHE)

    if (slcf->redirect_cache) {
      if (redirect) {
        if (location.len == redirect->data.value.len
          && ngx_memcmp(redirect->data.value.data, location.data,
                              location.len) == 0)
        {
          redirect->accessed = ngx_cached_time;
          redirect->updated = ngx_cached_time;

          /*
           * we can unlock the cache entry because
           * we have the local copy anyway
           */

          ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
          redirect_cleanup->valid = 0;

          return NGX_HTTP_MOVED_PERMANENTLY;
        }
      }

      location.len++;
      redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
                      redirect_cleanup,
                      &name, redirect_crc,
                      &location, log);
      location.len--;

      ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
               "http redirect cache alloc: " PTR_FMT, redirect);

      if (redirect) {
        redirect->fd = NGX_INVALID_FILE;
        redirect->accessed = ngx_cached_time;
        redirect->last_modified = 0;
        redirect->updated = ngx_cached_time;
        redirect->memory = 1;
        ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
        redirect_cleanup->valid = 0;
      }

    }

#endif

    return NGX_HTTP_MOVED_PERMANENTLY;
  }

#if !(WIN32) /* the not regular files are probably Unix specific */

  if (!ngx_is_file(&fi)) {
    ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
            "%s is not a regular file", name.data);

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    return NGX_HTTP_NOT_FOUND;
  }

#endif


#if (NGX_HTTP_CACHE)

  if (clcf->open_files) {

#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)

    if (file && file->uniq == ngx_file_uniq(&fi)) {
      if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                ngx_close_file_n " \"%s\" failed", name.data);
      }
      file->accessed = ngx_cached_time;
      file->updated = ngx_cached_time;
      file->expired = 0;
      r->cache = file;

      return ngx_http_send_cached(r);

    } else {
      if (file) {
        ngx_http_cache_unlock(clcf->open_files, file, log);
        file = NULL;
      }

      file = ngx_http_cache_alloc(clcf->open_files, file,
                    file_cleanup,
                    &name, file_crc, NULL, log);
      if (file) {
        file->uniq = ngx_file_uniq(&fi);
      }
    }

#else
    file = ngx_http_cache_alloc(clcf->open_files, file,
                  file_cleanup,
                  &name, file_crc, NULL, log);
#endif

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http open file cache alloc: " PTR_FMT, file);

    if (file) {
      file->fd = fd;
      file->data.size = ngx_file_size(&fi);
      file->accessed = ngx_cached_time;
      file->last_modified = ngx_file_mtime(&fi);
      file->updated = ngx_cached_time;
      r->cache = file;
    }

    return ngx_http_send_cached(r);
  }

#endif

  ctx = log->data;
  ctx->action = "sending response to client";

  file_cleanup->data.file.fd = fd;
  file_cleanup->data.file.name = name.data;
  file_cleanup->valid = 1;
  file_cleanup->cache = 0;

  r->headers_out.status = NGX_HTTP_OK;
  r->headers_out.content_length_n = ngx_file_size(&fi);
  r->headers_out.last_modified_time = ngx_file_mtime(&fi);

  if (r->headers_out.content_length_n == 0) {
    r->header_only = 1;
  }

  if (ngx_http_set_content_type(r) != NGX_OK) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

#if (NGX_SUPPRESS_WARN)
  b = NULL;
#endif

  if (!r->header_only) {
    /* we need to allocate all before the header would be sent */

    if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (!(b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->filter_allow_ranges = 1;
  }

  rc = ngx_http_send_header(r);

  if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
    return rc;
  }

  b->in_file = 1;

  if (!r->main) {
    b->last_buf = 1;
  }

  b->file_pos = 0;
  b->file_last = ngx_file_size(&fi);

  b->file->fd = fd;
  b->file->log = log;

  out.buf = b;
  out.next = NULL;

  return ngx_http_output_filter(r, &out);
}
static int
ngx_squ_file_write(squ_State *l)
{
    char                *errstr;
    size_t               size;
    u_char              *str;
    ngx_int_t            rc;
    ngx_buf_t           *b;
    ngx_file_t          *file;
    ngx_file_info_t      fi;
    ngx_squ_thread_t    *thr;
    ngx_squ_file_ctx_t  *ctx;

    thr = ngx_squ_thread(l);

    ngx_log_debug0(NGX_LOG_DEBUG_CORE, thr->log, 0, "squ file write");

    ctx = ngx_squ_file(l);

    file = &ctx->file;

    if (file->fd == NGX_INVALID_FILE) {
        errstr = "invalid fd";
        goto error;
    }

    ngx_memzero(&fi, sizeof(ngx_file_info_t));

    if (ngx_fd_info(file->fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, thr->log, ngx_errno,
                      ngx_fd_info_n " \"%V\" failed", &file->name);
        errstr = ngx_fd_info_n " failed";
        goto error;
    }

    size = (size_t) ngx_file_size(&fi);

    str = (u_char *) squL_checklstring(l, 2, &ctx->size);
    ctx->offset = squL_optint(l, 3, (squ_Integer) ctx->offset);

    if (ctx->offset < 0 || ctx->offset > size) {
        errstr = "invalid offset of the file";
        goto error;
    }

    b = ctx->out;

    if (b == NULL || (size_t) (b->end - b->start) < ctx->size) {
        if (b != NULL && (size_t) (b->end - b->start) > ctx->pool->max) {
            ngx_pfree(ctx->pool, b->start);
        }

        size = ngx_max(ngx_pagesize, ctx->size);

        b = ngx_create_temp_buf(ctx->pool, size);
        if (b == NULL) {
            errstr = "ngx_create_temp_buf() failed";
            goto error;
        }

        ctx->out = b;
    }

    ngx_memcpy(b->start, str, ctx->size);

    rc = ngx_squ_file_aio_write(thr, ctx);
    if (rc == NGX_AGAIN) {
        return squ_yield(l, 0);
    }

    return rc;

error:

    squ_pushboolean(l, 0);
    squ_pushstring(l, errstr);

    return 2;
}
static ngx_fd_t
ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
    ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log)
{
    ngx_fd_t         fd;
    ngx_err_t        err;
    ngx_file_info_t  fi, atfi;

    /*
     * To allow symlinks with the same owner, use openat() (followed
     * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare
     * uids between fstat() and fstatat().
     *
     * As there is a race between openat() and fstatat() we don't
     * know if openat() in fact opened symlink or not.  Therefore,
     * we have to compare uids even if fstatat() reports the opened
     * component isn't a symlink (as we don't know whether it was
     * symlink during openat() or not).
     */

    fd = ngx_openat_file(at_fd, name, mode, create, access);

    if (fd == NGX_INVALID_FILE) {
        return NGX_INVALID_FILE;
    }

    if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW)
        == NGX_FILE_ERROR)
    {
        err = ngx_errno;
        goto failed;
    }

#if (NGX_HAVE_O_PATH)
    if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) {
        err = ngx_errno;
        goto failed;
    }
#else
    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        err = ngx_errno;
        goto failed;
    }
#endif

    if (fi.st_uid != atfi.st_uid) {
        err = NGX_ELOOP;
        goto failed;
    }

    return fd;

failed:

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                      ngx_close_file_n " \"%V\" failed", name);
    }

    ngx_set_errno(err);

    return NGX_INVALID_FILE;
}
Exemple #13
0
static int
command_sendfile(ClientData clientData, Tcl_Interp *interp, int objc,
    Tcl_Obj *const objv[])
{
    ngx_buf_t *b;
    ngx_chain_t out;
    ngx_http_request_t *r = getrequest(clientData);
    ngx_file_info_t *fi;
    ngx_fd_t fd;
    const char *filename;
    int filename_len;
    int rc;

    if (objc != 2) {
        Tcl_WrongNumArgs(interp, 1, objv, "file");
        return TCL_ERROR;
    }

    filename = Tcl_GetStringFromObj(objv[1], &filename_len);

    fd = ngx_open_file(filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
    if (fd == NGX_INVALID_FILE) {
        Tcl_SetResult(interp, (char *) Tcl_PosixError(interp),
            TCL_VOLATILE);
        return TCL_ERROR;
    }

    b = ngx_calloc_buf(r->pool);
   if (b == NULL) {
        return TCL_ERROR;
    }

    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) {
        return TCL_ERROR;
    }

    fi = &b->file->info;
    ngx_fd_info(fd, fi);

    if (!r->header_sent) {
        r->headers_out.content_length_n = ngx_file_size(fi);
        r->headers_out.last_modified_time = ngx_file_mtime(fi);

        if (ngx_http_set_etag(r) != NGX_OK) {
            return TCL_ERROR;
        }

        ngx_http_send_header(r);
        /* TODO: CHECK RETURN */
    }

    r->allow_ranges = 1;

    b->file_pos = 0;
    b->file_last = ngx_file_size(fi);

    b->in_file = 1;
    b->last_buf = 1;
    b->last_in_chain = 1;

    b->file->fd = fd;
    b->file->name.data = (u_char*)filename;
    b->file->name.len = filename_len;
    b->file->log = r->connection->log;

    out.buf = b;
    out.next = NULL;

    rc = ngx_http_output_filter(r, &out);

    if (rc != NGX_OK) {
        ngx_tcl_set_error_code(interp, rc);
        return TCL_ERROR;
    }

    printf("ngx_http_output_filter returns %i\n", rc); fflush(stdout);

    return TCL_OK;
}
ngx_int_t ngx_http_cookie_conf_each_line_proc(ngx_http_cookie_clean_conf_t *conf,
                                                ngx_str_t *filename,
                                                each_line_proc proc,
                                                void * obj,
                                                void * p_data)
{
    ngx_int_t      rc = NGX_OK;

    ngx_file_t     file;
    ngx_str_t      full;
    ngx_fd_t       fd;
    off_t          file_size;
    ssize_t        n;

    ngx_buf_t      buf;
    u_char        *s = NULL;
    ngx_log_t     *log = conf->ctx->log;

    ngx_memzero(&file, sizeof(ngx_file_t));
    ngx_memzero(&full, sizeof(ngx_str_t));
    ngx_memzero(&buf, sizeof(ngx_buf_t));
    fd = NGX_INVALID_FILE;

    if (filename->len == 0) {
        ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], file not set", __FUNCTION__, __LINE__);
        return NGX_ERROR;
    }

    if (ngx_http_cookie_full_name(conf->ctx, filename, &full) != NGX_OK) {
        ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], get full file name of \"%V\" failed.",__FUNCTION__, __LINE__, filename);
        goto failed;
    }
    ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], full file name:\"%V\".", __FUNCTION__, __LINE__, &full);

    fd = ngx_open_file(full.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
    if (fd == NGX_INVALID_FILE) {
        ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], open file:\"%V\" failed.", __FUNCTION__, __LINE__, &full);
        goto failed;
    }

    if (ngx_fd_info(fd, &file.info) == NGX_FILE_ERROR) {
        ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], get file:\"%V\" info failed.", __FUNCTION__, __LINE__, &full);
        goto failed;
    }

    file.fd        = fd;
    file.name.data = full.data;
    file.name.len  = full.len;
    file.offset    = 0;
    file.log       = log;

    buf.start = ngx_alloc(NGX_HTTP_COOKIE_CLEAN_BUFFER, log);
    if (buf.start == NULL) {
        ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], alloc buffer failed.", __FUNCTION__, __LINE__);
        goto failed;
    }
    buf.pos       = buf.start;
    buf.last      = buf.start;
    buf.end       = buf.last + NGX_HTTP_COOKIE_CLEAN_BUFFER;
    buf.temporary = 1;

    file_size = ngx_file_size(&file.info);
    while (1) {
        s = ngx_http_cookie_read_one_line(&file, &buf, file_size, &n);
        if (n == -1) {
            ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], read file:\"%V\" failed.", __FUNCTION__, __LINE__, &full);
            goto failed;
        }
        if (n == 0) {
            break;
        }
        if (proc(conf, obj, s, n, p_data) != 0) {
            ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], proc one line:\"%*s\" failed.", __FUNCTION__, __LINE__,
                    n, s);
            goto failed;
        }
        ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], proc one line:\"%*s\" succeed.", __FUNCTION__, __LINE__,
                n, s);
    }
    ngx_log_debug(NGX_LOG_NOTICE, log, 0, "[%s:%d], proc file:\"%V\" succeed.", __FUNCTION__, __LINE__, &full);
    goto done;

failed:
    rc = NGX_ERROR;
done:
    if (full.data != NULL) {
        ngx_free(full.data);
        full.data = NULL;
    }
    if (fd != NGX_INVALID_FILE
            && ngx_close_file(fd) == NGX_FILE_ERROR) {
        rc = NGX_ERROR;
    }
    if (buf.start != NULL) {
        ngx_free(buf.start);
        buf.start = NULL;
    }
    return rc;
}
Exemple #15
0
static char *
ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_js_loc_conf_t *jlcf = conf;

    size_t                 size;
    u_char                *start, *end;
    ssize_t                n;
    ngx_fd_t               fd;
    ngx_str_t             *value, file;
    nxt_int_t              rc;
    nxt_str_t              text, ext, *export;
    nxt_lvlhsh_t           externals;
    ngx_file_info_t        fi;
    njs_vm_shared_t       *shared;
    ngx_pool_cleanup_t    *cln;
    nxt_mem_cache_pool_t  *mcp;

    if (jlcf->vm) {
        return "is duplicate";
    }

    value = cf->args->elts;
    file = value[1];

    if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    fd = ngx_open_file(file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
    if (fd == NGX_INVALID_FILE) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                           ngx_open_file_n " \"%s\" failed", file.data);
        return NGX_CONF_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", file.data);
        (void) ngx_close_file(fd);
        return NGX_CONF_ERROR;
    }

    size = ngx_file_size(&fi);

    start = ngx_pnalloc(cf->pool, size);
    if (start == NULL) {
        (void) ngx_close_file(fd);
        return NGX_CONF_ERROR;
    }

    n = ngx_read_fd(fd, start,  size);

    if (n == -1) {
        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                      ngx_read_fd_n " \"%s\" failed", file.data);

        (void) ngx_close_file(fd);
        return NGX_CONF_ERROR;
    }

    if ((size_t) n != size) {
        ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                      ngx_read_fd_n " has read only %z of %O from \"%s\"",
                      n, size, file.data);

        (void) ngx_close_file(fd);
        return NGX_CONF_ERROR;
    }

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                      ngx_close_file_n " %s failed", file.data);
    }

    end = start + size;

    mcp = ngx_http_js_create_mem_cache_pool();
    if (mcp == NULL) {
        return NGX_CONF_ERROR;
    }

    cln = ngx_pool_cleanup_add(cf->pool, 0);
    if (cln == NULL) {
        return NULL;
    }

    cln->handler = ngx_http_js_cleanup_mem_cache_pool;
    cln->data = mcp;

    shared = NULL;

    nxt_lvlhsh_init(&externals);

    if (njs_vm_external_add(&externals, mcp, 0, ngx_http_js_externals,
                            nxt_nitems(ngx_http_js_externals))
        != NJS_OK)
    {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals");
        return NGX_CONF_ERROR;
    }

    jlcf->vm = njs_vm_create(mcp, &shared, &externals);
    if (jlcf->vm == NULL) {
        return NGX_CONF_ERROR;
    }

    rc = njs_vm_compile(jlcf->vm, &start, end, NULL, &export);

    if (rc != NJS_OK) {
        njs_vm_exception(jlcf->vm, &text);

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "%*s, included",
                           text.length, text.start);
        return NGX_CONF_ERROR;
    }

    if (start != end) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "extra characters in js script: \"%*s\", included",
                           end - start, start);
        return NGX_CONF_ERROR;
    }

    ext = nxt_string_value("$r");

    if (njs_vm_external(jlcf->vm, NULL, &ext, &jlcf->args[0]) != NJS_OK) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "js external \"%*s\" not found",
                           ext.length, ext.start);
        return NGX_CONF_ERROR;
    }

    ext = nxt_string_value("response");

    rc = njs_vm_external(jlcf->vm, &jlcf->args[0], &ext, &jlcf->args[1]);
    if (rc != NXT_OK) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "js external \"$r.%*s\" not found",
                           ext.length, ext.start);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{	//第二个数为保存的配置文件路径的字符串,如/usr/local/nginx/conf/nginx.conf_file

    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf;
    ngx_conf_file_t  *prev, conf_file;
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {		//指向一个配置文件路径字符串,需要函数ngx_conf_parse打开该文件并获取相关的文件信息

        /* open configuration file */

        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

        prev = cf->conf_file;

        cf->conf_file = &conf_file;

        if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

        cf->conf_file->buffer = &buf;

        buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);	//内存
        if (buf.start == NULL) {
            goto failed;
        }

        buf.pos = buf.start;		//初始值
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;	//4K,到末尾
        buf.temporary = 1;

        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        type = parse_file;  //刚刚打开的新文件,包括include指令

    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

		//说明此时仅解析了部分解析,当遇到复杂配置项,比如events,http等,此时解析的内容还是来自当前文件
        type = parse_block;

    } else {

		//正要开始解析命令行参数配置项值,在对用户通过命令行-g参数输入的配置信息进行解析,如nginx -g 'daemon on'
        type = parse_param;
    }


    for ( ;; ) {
        rc = ngx_conf_read_token(cf);		//读取token,每次读取一个buffer

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        if (rc == NGX_CONF_BLOCK_DONE) {	//解析正常

            if (type != parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_FILE_DONE) {

            if (type == parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "unexpected end of file, expecting \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_BLOCK_START) {

            if (type == parse_param) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "block directives are not supported "
                                   "in -g option");
                goto failed;
            }
        }

        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

        if (cf->handler) {		//进行这些token转换为Nginx内控制变量的值,针对“text/html html htm shtml”等这样的配置项或geo模块里的“192.168.0.0/16 local”这样的不定配置项,进行特殊的处理

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);	
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }


        rc = ngx_conf_handler(cf, rc);		//配置转换

        if (rc == NGX_ERROR) {
            goto failed;
        }
    }

failed:

    rc = NGX_ERROR;

done:

    if (filename) {
        if (cf->conf_file->buffer->start) {
            ngx_free(cf->conf_file->buffer->start);
        }

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          filename->data);
            return NGX_CONF_ERROR;
        }

        cf->conf_file = prev;
    }

    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
Exemple #17
0
static void
ngx_pipe_log(ngx_cycle_t *cycle, ngx_open_pipe_t *op)
{
    ngx_int_t                   n_bytes_read;
    u_char                     *read_buf;
    size_t                      read_buf_len = 65536;
    ngx_fd_t                    log_fd = NGX_INVALID_FILE;
#ifdef T_PIPE_NO_DISPLAY
    size_t                      title_len;
#endif
    ngx_pipe_rollback_conf_t    rbcf;
    ngx_file_info_t             sb;
    size_t                      one_day = 24 * 60 * 60;

    ngx_pid = ngx_getpid();

    rbcf.last_open_time = 0;
    rbcf.last_suit_time = 0;
    rbcf.log_size = 0;

    if (ngx_pipe_rollback_parse_args(cycle, op, &rbcf) != NGX_OK) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "log rollback parse error");
        return;
    }

    read_buf = ngx_pcalloc(cycle->pool, read_buf_len);
    if (read_buf == NULL) {
        return;
    }

    //set title
    ngx_setproctitle((char *) op->cmd);
#ifdef T_PIPE_NO_DISPLAY
    title_len = ngx_strlen(ngx_os_argv[0]);
#if (NGX_SOLARIS)
#else
    ngx_memset((u_char *) ngx_os_argv[0], NGX_SETPROCTITLE_PAD, title_len);
    ngx_cpystrn((u_char *) ngx_os_argv[0], op->cmd, title_len);
#endif
#endif

    for (;;)
    {
        if (ngx_terminate == 1) {
            return;
        }

        n_bytes_read = ngx_read_fd(0, read_buf, read_buf_len);
        if (n_bytes_read == 0) {
            return;
        }
        if (errno == EINTR) {
            continue;

        } else if (n_bytes_read < 0) {
            return;
        }

        rbcf.time_now = ngx_pipe_get_now_sec();

        if (NULL != rbcf.suitpath) {
            if (rbcf.time_now / one_day >
                    rbcf.last_suit_time / one_day) {
                ngx_pipe_create_suitpath(cycle, &rbcf);
            }
        }

        if (log_fd >= 0) {
            if (rbcf.interval > 0) {
                if (((rbcf.time_now - rbcf.adjust_time) / rbcf.interval) >
                        (rbcf.last_open_time / rbcf.interval)) {
                    //need check rollback
                    ngx_close_file(log_fd);
                    log_fd = NGX_INVALID_FILE;
                    ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                                  "need check rollback time [%s]", rbcf.logname);
                    ngx_pipe_do_rollback(cycle, &rbcf);
                }
            }
        }

        if (log_fd >= 0 && rbcf.log_max_size > 0 &&
                           rbcf.log_size >= rbcf.log_max_size) {
            ngx_close_file(log_fd);
            log_fd = NGX_INVALID_FILE;
            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                          "need check rollback size [%s] [%d]",
                          rbcf.logname, rbcf.log_size);
            ngx_pipe_do_rollback(cycle, &rbcf);
        }

        /* If there is no log file open then open a new one.
         *   */
        if (log_fd < 0) {
            ngx_pipe_create_subdirs(rbcf.logname, cycle);
            if (rbcf.interval > 0 && rbcf.last_open_time == 0 
                    && ((rbcf.time_now - rbcf.adjust_time_raw) / rbcf.interval < rbcf.time_now / rbcf.interval)) { /*just check
                when time is after interval and befor adjust_time_raw, fix when no backup file, do rollback
                */
                //need check last rollback time, because other process may do rollback after when it adjust time more than this process
                ngx_pipe_get_last_rollback_time(&rbcf);
            } else {
                rbcf.last_open_time = ngx_pipe_get_now_sec();
            }

            log_fd = ngx_open_file(rbcf.logname, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
                          NGX_PIPE_FILE_ACCESS);
            if (log_fd < 0) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              "open [%s] failed", rbcf.logname);
                return;
            }

            if (0 == ngx_fd_info(log_fd, &sb)) {
                rbcf.log_size = sb.st_size;
            }
        }

        if (ngx_write_fd(log_fd, read_buf, n_bytes_read) != n_bytes_read) {
            if (errno != EINTR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              "write to [%s] failed", rbcf.logname);
                return;
            }
        }
        rbcf.log_size += n_bytes_read;
    }

}
static ngx_int_t
ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
{
    int              mode;
    ngx_fd_t         fd;
    ngx_file_info_t  fi;

    if (of->fd != NGX_INVALID_FILE) {

        if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
            of->failed = ngx_file_info_n;
            goto failed;
        }

        if (of->uniq == ngx_file_uniq(&fi)) {
            goto done;
        }

    } else if (of->test_dir) {

        if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
            of->failed = ngx_file_info_n;
            goto failed;
        }

        if (ngx_is_dir(&fi)) {
            goto done;
        }
    }

    if (!of->log) {

        /*
         * Use non-blocking open() not to hang on FIFO files, etc.
         * This flag has no effect on a regular files.
         */

        mode = NGX_FILE_RDONLY|NGX_FILE_NONBLOCK;

#if (NGX_WIN32 && NGX_HAVE_FILE_AIO)
        if (ngx_event_flags & NGX_USE_IOCP_EVENT && of->aio) {
            mode |= NGX_FILE_OVERLAPPED;
        }
#endif

        fd = ngx_open_file(name, mode, NGX_FILE_OPEN, 0);

    } else {
        fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
                           NGX_FILE_DEFAULT_ACCESS);
    }

    if (fd == NGX_INVALID_FILE) {
        of->failed = ngx_open_file_n;
        goto failed;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", name);

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        of->fd = NGX_INVALID_FILE;

        return NGX_ERROR;
    }

    if (ngx_is_dir(&fi)) {
        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        of->fd = NGX_INVALID_FILE;

    } else {
        of->fd = fd;

        if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) {
            if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                              ngx_read_ahead_n " \"%s\" failed", name);
            }
        }

        if (of->directio <= ngx_file_size(&fi)) {
            if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                              ngx_directio_on_n " \"%s\" failed", name);

            } else {
                of->is_directio = 1;
            }
        }
    }

done:

    of->uniq = ngx_file_uniq(&fi);
    of->mtime = ngx_file_mtime(&fi);
    of->size = ngx_file_size(&fi);
    of->fs_size = ngx_file_fs_size(&fi);
    of->is_dir = ngx_is_dir(&fi);
    of->is_file = ngx_is_file(&fi);
    of->is_link = ngx_is_link(&fi);
    of->is_exec = ngx_is_exec(&fi);

    return NGX_OK;

failed:

    of->fd = NGX_INVALID_FILE;
    of->err = ngx_errno;

    return NGX_ERROR;
}
Exemple #19
0
ngx_int_t
ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
{
    char             *buf;
    off_t             size;
    size_t            len;
    ssize_t           n;
    ngx_fd_t          fd, nfd;
    ngx_int_t         rc;
    ngx_file_info_t   fi;

    rc = NGX_ERROR;
    buf = NULL;
    nfd = NGX_INVALID_FILE;

    fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
                      ngx_open_file_n " \"%s\" failed", from);
        goto failed;
    }

    if (cf->size != -1) {
        size = cf->size;

    } else {
        if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", from);

            goto failed;
        }

        size = ngx_file_size(&fi);
    }

    len = cf->buf_size ? cf->buf_size : 65536;

    if ((off_t) len > size) {
        len = (size_t) size;
    }

    buf = ngx_alloc(len, cf->log);
    if (buf == NULL) {
        goto failed;
    }

    nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
                        cf->access);

    if (nfd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
                      ngx_open_file_n " \"%s\" failed", to);
        goto failed;
    }

    while (size > 0) {

        if ((off_t) len > size) {
            len = (size_t) size;
        }

        n = ngx_read_fd(fd, buf, len);

        if (n == -1) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_read_fd_n " \"%s\" failed", from);
            goto failed;
        }

        if ((size_t) n != len) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                          ngx_read_fd_n " has read only %z of %uz from %s",
                          n, size, from);
            goto failed;
        }

        n = ngx_write_fd(nfd, buf, len);

        if (n == -1) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_write_fd_n " \"%s\" failed", to);
            goto failed;
        }

        if ((size_t) n != len) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                          ngx_write_fd_n " has written only %z of %uz to %s",
                          n, size, to);
            goto failed;
        }

        size -= n;
    }

    if (cf->time != -1) {
        if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_set_file_time_n " \"%s\" failed", to);
            goto failed;
        }
    }

    rc = NGX_OK;

failed:

    if (nfd != NGX_INVALID_FILE) {
        if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", to);
        }
    }

    if (fd != NGX_INVALID_FILE) {
        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", from);
        }
    }

    if (buf) {
        ngx_free(buf);
    }

    return rc;
}
/*
 * 解析配置文件
 */
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf;
    ngx_conf_file_t  *prev, conf_file;
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {                     //新的配置文件

        /* open configuration file */

        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);          //打开文件
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

        prev = cf->conf_file;

        cf->conf_file = &conf_file;

        if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

        cf->conf_file->buffer = &buf;

        buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);                //默认4K的缓冲区
        if (buf.start == NULL) {
            goto failed;
        }

        buf.pos = buf.start;
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;
        buf.temporary = 1;

        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        type = parse_file;

    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

        type = parse_block;

    } else {
        type = parse_param;
    }


    for ( ;; ) {
        rc = ngx_conf_read_token(cf);                                   //读取配置项

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        if (rc == NGX_CONF_BLOCK_DONE) {

            if (type != parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_FILE_DONE) {

            if (type == parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "unexpected end of file, expecting \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_BLOCK_START) {

            if (type == parse_param) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "block directives are not supported "
                                   "in -g option");
                goto failed;
            }
        }

        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

        if (cf->handler) {

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */

            if (rc == NGX_CONF_BLOCK_START) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
                goto failed;
            }

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }

        /*解析配置项*/
        rc = ngx_conf_handler(cf, rc);

        if (rc == NGX_ERROR) {
            goto failed;
        }
    }

failed:

    rc = NGX_ERROR;

done:

    /*配置文件协议完毕,释放相应数据空间*/
    if (filename) {
        if (cf->conf_file->buffer->start) {
            ngx_free(cf->conf_file->buffer->start);
        }

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          filename->data);
            rc = NGX_ERROR;
        }

        cf->conf_file = prev;
    }

    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
Exemple #21
0
static ngx_int_t
ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name)
{
    u_char                        *p;
    ngx_fd_t                       fd;
    ngx_int_t                      n;
    ngx_uint_t                     i;
    ngx_file_info_t                fi;
    ngx_http_cache_t               c;
    ngx_http_file_cache_t         *cache;
    ngx_http_file_cache_header_t   h;

    if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) {
        return NGX_ERROR;
    }

    ngx_memzero(&c, sizeof(ngx_http_cache_t));

    fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
                      ngx_open_file_n " \"%s\" failed", name->data);
        return NGX_ERROR;
    }

    c.file.fd = fd;
    c.file.name = *name;
    c.file.log = ctx->log;

    n = ngx_read_file(&c.file, (u_char *) &h,
                      sizeof(ngx_http_file_cache_header_t), 0);
    if (n == NGX_ERROR) {
        return NGX_ERROR;
    }

    if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) {
        ngx_log_error(NGX_LOG_CRIT, ctx->log, 0,
                      "cache file \"%s\" is too small", name->data);
        return NGX_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", name->data);

    } else {
        c.uniq = ngx_file_uniq(&fi);
        c.valid_sec = h.valid_sec;
        c.valid_msec = h.valid_msec;
        c.body_start = h.body_start;
        c.length = ngx_file_size(&fi);
    }

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
                      ngx_close_file_n " \"%s\" failed", name->data);
    }

    if (c.body_start == 0) {
        return NGX_ERROR;
    }

    p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN];

    for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) {
        n = ngx_hextoi(p, 2);

        if (n == NGX_ERROR) {
            return NGX_ERROR;
        }

        p += 2;

        c.key[i] = (u_char) n;
    }

    cache = ctx->data;

    return ngx_http_file_cache_add(cache, &c);
}
void
ngx_http_file_cache_update_header(ngx_http_request_t *r)
{
    ssize_t                        n;
    ngx_err_t                      err;
    ngx_file_t                     file;
    ngx_file_info_t                fi;
    ngx_http_cache_t              *c;
    ngx_http_file_cache_header_t   h;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache update header");

    c = r->cache;

    ngx_memzero(&file, sizeof(ngx_file_t));

    file.name = c->file.name;
    file.log = r->connection->log;
    file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);

    if (file.fd == NGX_INVALID_FILE) {
        err = ngx_errno;

        /* cache file may have been deleted */

        if (err == NGX_ENOENT) {
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http file cache \"%s\" not found",
                           file.name.data);
            return;
        }

        ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
                      ngx_open_file_n " \"%s\" failed", file.name.data);
        return;
    }

    /*
     * make sure cache file wasn't replaced;
     * if it was, do nothing
     */

    if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", file.name.data);
        goto done;
    }

    if (c->uniq != ngx_file_uniq(&fi)
            || c->length != ngx_file_size(&fi))
    {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http file cache \"%s\" changed",
                       file.name.data);
        goto done;
    }

    n = ngx_read_file(&file, (u_char *) &h,
                      sizeof(ngx_http_file_cache_header_t), 0);

    if (n == NGX_ERROR) {
        goto done;
    }

    if ((size_t) n != sizeof(ngx_http_file_cache_header_t)) {
        ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
                      ngx_read_file_n " read only %z of %z from \"%s\"",
                      n, sizeof(ngx_http_file_cache_header_t), file.name.data);
        goto done;
    }

    if (h.last_modified != c->last_modified
            || h.crc32 != c->crc32
            || h.header_start != c->header_start
            || h.body_start != c->body_start)
    {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http file cache \"%s\" content changed",
                       file.name.data);
        goto done;
    }

    /*
     * update cache file header with new data,
     * notably h.valid_sec and h.date
     */

    ngx_memzero(&h, sizeof(ngx_http_file_cache_header_t));

    h.valid_sec = c->valid_sec;
    h.last_modified = c->last_modified;
    h.date = c->date;
    h.crc32 = c->crc32;
    h.valid_msec = (u_short) c->valid_msec;
    h.header_start = (u_short) c->header_start;
    h.body_start = (u_short) c->body_start;

    (void) ngx_write_file(&file, (u_char *) &h,
                          sizeof(ngx_http_file_cache_header_t), 0);

done:

    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                      ngx_close_file_n " \"%s\" failed", file.name.data);
    }
}
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    u_char           *p;
    off_t             size;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf, *tbuf;
    ngx_conf_file_t  *prev, conf_file;
    ngx_conf_dump_t  *cd;
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {

        /* open configuration file */

        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

        prev = cf->conf_file;

        cf->conf_file = &conf_file;

        if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

        cf->conf_file->buffer = &buf;

        buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
        if (buf.start == NULL) {
            goto failed;
        }

        buf.pos = buf.start;
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;
        buf.temporary = 1;

        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        type = parse_file;

        if (ngx_dump_config
#if (NGX_DEBUG)
            || 1
#endif
           )
        {
            p = ngx_pstrdup(cf->cycle->pool, filename);
            if (p == NULL) {
                goto failed;
            }

            size = ngx_file_size(&cf->conf_file->file.info);

            tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
            if (tbuf == NULL) {
                goto failed;
            }

            cd = ngx_array_push(&cf->cycle->config_dump);
            if (cd == NULL) {
                goto failed;
            }

            cd->name.len = filename->len;
            cd->name.data = p;
            cd->buffer = tbuf;

            cf->conf_file->dump = tbuf;

        } else {
            cf->conf_file->dump = NULL;
        }

    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

        type = parse_block;

    } else {
        type = parse_param;
    }


    /*这里解析指令的方式是"读取一条、检查一条、解析一条"的方式解析配置文件,这里的一条是以分号或者花括号"{"、"}"为单位,如果遇到嵌套的花括号,则先处理嵌套的指令*/
    for ( ;; ) {
        /*将配置文件中当前的一条配置指令读取到内存中,判断配置语法是否使用正确,并将该指令保存到cycle->args数组中*/
        rc = ngx_conf_read_token(cf);

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        if (rc == NGX_CONF_BLOCK_DONE) {

            if (type != parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_FILE_DONE) {

            if (type == parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "unexpected end of file, expecting \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_BLOCK_START) {

            if (type == parse_param) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "block directives are not supported "
                                   "in -g option");
                goto failed;
            }
        }

        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

        /*如果该指令定义了自定义处理函数,则调用自定义处理函数进行解析*/
        if (cf->handler) {

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */

            if (rc == NGX_CONF_BLOCK_START) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
                goto failed;
            }

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }


        /*调用指令的处理函数*/
        rc = ngx_conf_handler(cf, rc);

        if (rc == NGX_ERROR) {
            goto failed;
        }
    }

failed:

    rc = NGX_ERROR;

done:

    if (filename) {
        if (cf->conf_file->buffer->start) {
            ngx_free(cf->conf_file->buffer->start);
        }

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          filename->data);
            rc = NGX_ERROR;
        }

        cf->conf_file = prev;
    }

    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static ngx_int_t
ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of,
    ngx_log_t *log)
{
    ngx_fd_t         fd;
    ngx_file_info_t  fi;

    if (of->fd != NGX_INVALID_FILE) {

        if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) {
            of->fd = NGX_INVALID_FILE;
            return NGX_ERROR;
        }
		// 判断文件是否被改变
        if (of->uniq == ngx_file_uniq(&fi)) {
            goto done;
        }

    } else if (of->test_dir) {

        if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) {
            of->fd = NGX_INVALID_FILE;
            return NGX_ERROR;
        }

        if (ngx_is_dir(&fi)) {
            goto done;
        }
    }
	// 否则重新打开
    if (!of->log) {

        /*
         * Use non-blocking open() not to hang on FIFO files, etc.
         * This flag has no effect on a regular files.
         */

        fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
                                   NGX_FILE_OPEN, 0, log);

    } else {
        fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND,
                                   NGX_FILE_CREATE_OR_OPEN,
                                   NGX_FILE_DEFAULT_ACCESS, log);
    }

    if (fd == NGX_INVALID_FILE) {
        of->fd = NGX_INVALID_FILE;
        return NGX_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                      ngx_fd_info_n " \"%V\" failed", name);

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%V\" failed", name);
        }

        of->fd = NGX_INVALID_FILE;

        return NGX_ERROR;
    }

    if (ngx_is_dir(&fi)) {
        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%V\" failed", name);
        }

        of->fd = NGX_INVALID_FILE;

    } else {
        of->fd = fd;

        if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) {
            if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                              ngx_read_ahead_n " \"%V\" failed", name);
            }
        }

        if (of->directio <= ngx_file_size(&fi)) {
            if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                              ngx_directio_on_n " \"%V\" failed", name);

            } else {
                of->is_directio = 1;
            }
        }
    }

done:

    of->uniq = ngx_file_uniq(&fi);
    of->mtime = ngx_file_mtime(&fi);
    of->size = ngx_file_size(&fi);
    of->fs_size = ngx_file_fs_size(&fi);
    of->is_dir = ngx_is_dir(&fi);
    of->is_file = ngx_is_file(&fi);
    of->is_link = ngx_is_link(&fi);
    of->is_exec = ngx_is_exec(&fi);

    return NGX_OK;
}
int
ngx_http_lua_clfactory_bytecode_prepare(lua_State *L,
    ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index)
{
    int                 x = 1, size_of_int, size_of_size_t, little_endian,
                        size_of_inst, version, stripped;
    static int          num_of_inst = 3, num_of_inter_func = 1;
    const char         *filename, *emsg, *serr, *bytecode;
    size_t              size, bytecode_len;
    ngx_file_info_t     fi;

    serr = NULL;

    *lf->begin_code.str = LUA_SIGNATURE[0];

    if (lf->file_type == NGX_LUA_BT_LJ) {
        size = fread(lf->begin_code.str + 1, 1, LJ_HEADERSIZE - 1, lf->f);

        if (size != LJ_HEADERSIZE - 1) {
            serr = strerror(errno);
            emsg = "cannot read header";
            goto error;
        }

        version = *(lf->begin_code.str + 3);

        if (ngx_memcmp(lf->begin_code.str, LJ_SIGNATURE,
                       sizeof(LJ_SIGNATURE) - 1)
            || version != LJ_BCDUMP_VERSION)
        {
            emsg = "bad byte-code header";
            goto error;
        }

#if defined(DDEBUG) && (DDEBUG)
        {
        dd("==LJ_BT_HEADER==");
        size_t i;
        for (i = 0; i < LJ_HEADERSIZE; i++) {
            dd("%ld: 0x%02X", i, (unsigned)(u_char)lf->begin_code.str[i]);
        }
        dd("==LJ_BT_HEADER_END==");
        }
#endif

        lf->begin_code_len = LJ_HEADERSIZE;
        little_endian = !((*(lf->begin_code.str + 4)) & LJ_BCDUMP_F_BE);
        stripped = (*(lf->begin_code.str + 4)) & LJ_BCDUMP_F_STRIP;

        if (stripped) {
            if (little_endian) {
                lf->end_code.ptr = LJ_LITTLE_ENDIAN_CODE_STRIPPED;

            } else {
                lf->end_code.ptr = LJ_BIG_ENDIAN_CODE_STRIPPED;
            }

            lf->end_code_len = LJ_CODE_LEN_STRIPPED;

        } else {
            if (little_endian) {
                lf->end_code.ptr = LJ_LITTLE_ENDIAN_CODE;

            } else {
                lf->end_code.ptr = LJ_BIG_ENDIAN_CODE;
            }

            lf->end_code_len = LJ_CODE_LEN;
        }

        if (ngx_fd_info(fileno(lf->f), &fi) == NGX_FILE_ERROR) {
            serr = strerror(errno);
            emsg = "cannot fstat";
            goto error;
        }

        lf->rest_len = ngx_file_size(&fi) - LJ_HEADERSIZE;

#if defined(DDEBUG) && (DDEBUG)
        {
        size_t i = 0;
        dd("==LJ_END_CODE: %ld rest_len: %ld==", lf->end_code_len,
           lf->rest_len);

        for (i = 0; i < lf->end_code_len; i++) {
            dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->end_code.ptr[i]));
        }
        dd("==LJ_END_CODE_END==");
        }
#endif

    } else {
        size = fread(lf->begin_code.str + 1, 1, LUAC_HEADERSIZE - 1, lf->f);

        if (size != LUAC_HEADERSIZE - 1) {
            serr = strerror(errno);
            emsg = "cannot read header";
            goto error;
        }

        version = *(lf->begin_code.str + 4);
        little_endian = *(lf->begin_code.str + 6);
        size_of_int = *(lf->begin_code.str + 7);
        size_of_size_t = *(lf->begin_code.str + 8);
        size_of_inst = *(lf->begin_code.str + 9);

#if defined(DDEBUG) && (DDEBUG)
        {
        dd("==LUA_BT_HEADER==");
        size_t i;
        for (i = 0; i < LUAC_HEADERSIZE; i++) {
            dd("%ld, 0x%02X", i, (unsigned)(u_char)lf->begin_code.str[i]);
        }
        dd("==LUA_BT_HEADER_END==");
        }
#endif

        if (ngx_memcmp(lf->begin_code.str, LUA_SIGNATURE,
                       sizeof(LUA_SIGNATURE) -1)
            || version != LUAC_VERSION
            || little_endian != (int) (*(char *) &x)
            || size_of_int != sizeof(int)
            || size_of_size_t != sizeof(size_t)
            || (size_of_inst != 4 && size_of_inst != 8))
        {
            emsg = "bad byte-code header";
            goto error;
        }

        /* clear the following fields to zero:
         * - source string length
         * - start line
         * - last line
         */
        ngx_memzero(lf->begin_code.str + POS_SOURCE_STR_LEN,
                    sizeof(size_t) + sizeof(int) * 2);
        /* number of upvalues */
        *(lf->begin_code.str + POS_NUM_OF_UPVS) = 0;
        /* number of paramters */
        *(lf->begin_code.str + POS_NUM_OF_PARA) = 0;
        /* is var-argument function? */
        *(lf->begin_code.str + POS_IS_VAR_ARG) = 2;
        /* max stack size */
        *(lf->begin_code.str + POS_MAX_STACK_SIZE) = 2;
        /* number of bytecode instructions */
        ngx_memcpy(lf->begin_code.str + POS_NUM_OF_INST, &num_of_inst,
                   sizeof(int));

        lf->begin_code_len = POS_BYTECODE;

        if (little_endian) {
            if (size_of_inst == 4) {
                bytecode = LUA_LITTLE_ENDIAN_4BYTES_CODE;
                bytecode_len = LUA_LITTLE_ENDIAN_4BYTES_CODE_LEN;

            } else {
                bytecode = LUA_LITTLE_ENDIAN_8BYTES_CODE;
                bytecode_len = LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN;
            }

        } else {
            if (size_of_inst == 4) {
                bytecode = LUA_BIG_ENDIAN_4BYTES_CODE;
                bytecode_len = LUA_BIG_ENDIAN_4BYTES_CODE_LEN;

            } else {
                bytecode = LUA_BIG_ENDIAN_8BYTES_CODE;
                bytecode_len = LUA_BIG_ENDIAN_8BYTES_CODE_LEN;
            }
        }

        /* bytecode */
        ngx_memcpy(lf->begin_code.str + POS_BYTECODE, bytecode, bytecode_len);

        /* number of consts */
        ngx_memzero(lf->begin_code.str + POS_BYTECODE + bytecode_len,
                    sizeof(int));
        /* number of internal functions */
        ngx_memcpy(lf->begin_code.str + POS_BYTECODE + bytecode_len
                   + sizeof(int), &num_of_inter_func, sizeof(int));

        lf->begin_code_len += bytecode_len + sizeof(int) + sizeof(int);

#if defined(DDEBUG) && (DDEBUG)
        {
        size_t i = 0;
        dd("==LUA_BEGIN_CODE: %ld==", lf->begin_code_len);
        for (i = 0; i < lf->begin_code_len; i++) {
            dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->begin_code.str[i]));
        }
        dd("==LUA_BEGIN_CODE_END==");
        }
#endif

        /* clear the following fields to zero:
         * - lineinfo vector size
         * - number of local vars
         * - number of upvalues
         */
        ngx_memzero(lf->end_code.str, sizeof(int) * 3);

        lf->end_code_len = sizeof(int) + sizeof(int) + sizeof(int);

#if defined(DDEBUG) && (DDEBUG)
        {
        size_t i = 0;
        dd("==LUA_END_CODE: %ld==", lf->end_code_len);
        for (i = 0; i < lf->end_code_len; i++) {
            dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->end_code.str[i]));
        }
        dd("==LUA_END_CODE_END==");
        }
#endif

    }

    return 0;

error:

    fclose(lf->f);  /* close file (even in case of errors) */

    filename = lua_tostring(L, fname_index) + 1;

    if (serr) {
        lua_pushfstring(L, "%s in %s: %s", emsg, filename, serr);

    } else {
        lua_pushfstring(L, "%s in %s", emsg, filename);
    }

    lua_remove(L, fname_index);

    return LUA_ERRFILE;
}
Exemple #26
0
char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    int               m, rc, found, valid;
    char             *rv;
    void             *conf, **confp;
    ngx_fd_t          fd;
    ngx_str_t        *name;
    ngx_conf_file_t  *prev;
    ngx_command_t    *cmd;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename)
    {

        /* open configuration file */

        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
        if (fd == NGX_INVALID_FILE)
        {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_open_file_n " %s failed", filename->data);
            return NGX_CONF_ERROR;
        }

        prev = cf->conf_file;
        if (!(cf->conf_file = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t))))
        {
            return NGX_CONF_ERROR;
        }

        if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1)
        {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " %s failed", filename->data);
        }

        if (!(cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, 1024)))
        {
            return NGX_CONF_ERROR;
        }

        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;;
        cf->conf_file->line = 1;
    }

    for ( ;; )
    {
        rc = ngx_conf_read_token(cf);

        /*
         * ngx_conf_read_token() returns NGX_OK, NGX_ERROR,
         * NGX_CONF_FILE_DONE or NGX_CONF_BLOCK_DONE
         */

#if 0
        ngx_log_debug(cf->log, "token %d" _ rc);
#endif

        if (rc == NGX_ERROR)
        {
            break;
        }

        if (rc != NGX_OK)
        {
            break;
        }

        if (cf->handler)
        {

            /* custom handler, i.e. used in http "types { ... }" directive */

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK)
            {
                continue;

            }
            else if (rv == NGX_CONF_ERROR)
            {
                rc = NGX_ERROR;
                break;

            }
            else
            {
                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                              "%s in %s:%d",
                              rv,
                              cf->conf_file->file.name.data,
                              cf->conf_file->line);
                rc = NGX_ERROR;
                break;
            }
        }

        name = (ngx_str_t *) cf->args->elts;
        found = 0;

        for (m = 0; rc != NGX_ERROR && !found && ngx_modules[m]; m++)
        {

            /* look up the directive in the appropriate modules */

            if (ngx_modules[m]->type != NGX_CONF_MODULE
                    && ngx_modules[m]->type != cf->module_type)
            {
                continue;
            }

            cmd = ngx_modules[m]->commands;
            if (cmd == NULL)
            {
                continue;
            }

            while (cmd->name.len)
            {
                if (name->len == cmd->name.len
                        && ngx_strcmp(name->data, cmd->name.data) == 0)
                {

                    found = 1;
#if 0
                    ngx_log_debug(cf->log, "command '%s'" _ cmd->name.data);
#endif
                    /* is the directive's location right ? */

                    if ((cmd->type & cf->cmd_type) == 0)
                    {
                        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                                      "directive \"%s\" in %s:%d "
                                      "is not allowed here",
                                      name->data,
                                      cf->conf_file->file.name.data,
                                      cf->conf_file->line);
                        rc = NGX_ERROR;
                        break;
                    }

                    /* is the directive's argument count right ? */

                    if (cmd->type & NGX_CONF_ANY)
                    {
                        valid = 1;

                    }
                    else if (cmd->type & NGX_CONF_FLAG)
                    {

                        if (cf->args->nelts == 2)
                        {
                            valid = 1;
                        }
                        else
                        {
                            valid = 0;
                        }

                    }
                    else if (cmd->type & NGX_CONF_1MORE)
                    {

                        if (cf->args->nelts > 1)
                        {
                            valid = 1;
                        }
                        else
                        {
                            valid = 0;
                        }

                    }
                    else if (cmd->type & NGX_CONF_2MORE)
                    {

                        if (cf->args->nelts > 2)
                        {
                            valid = 1;
                        }
                        else
                        {
                            valid = 0;
                        }

                    }
                    else if (cf->args->nelts <= 10
                             && (cmd->type
                                 & argument_number[cf->args->nelts - 1]))
                    {
                        valid = 1;

                    }
                    else
                    {
                        valid = 0;
                    }

                    if (!valid)
                    {
                        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                                      "invalid number arguments in "
                                      "directive \"%s\" in %s:%d",
                                      name->data,
                                      cf->conf_file->file.name.data,
                                      cf->conf_file->line);
                        rc = NGX_ERROR;
                        break;
                    }

                    /* set up the directive's configuration context */

                    conf = NULL;

                    if (cmd->type & NGX_DIRECT_CONF)
                    {
                        conf = ((void **) cf->ctx)[ngx_modules[m]->index];

                    }
                    else if (cmd->type & NGX_MAIN_CONF)
                    {
                        conf = &(((void **) cf->ctx)[ngx_modules[m]->index]);

                    }
                    else if (cf->ctx)
                    {
                        confp = *(void **) ((char *) cf->ctx + cmd->conf);

                        if (confp)
                        {
                            conf = confp[ngx_modules[m]->ctx_index];
                        }
                    }

                    rv = cmd->set(cf, cmd, conf);

#if 0
                    ngx_log_debug(cf->log, "rv: %d" _ rv);
#endif

                    if (rv == NGX_CONF_OK)
                    {
                        break;

                    }
                    else if (rv == NGX_CONF_ERROR)
                    {
                        rc = NGX_ERROR;
                        break;

                    }
                    else
                    {
                        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                                      "the \"%s\" directive %s in %s:%d",
                                      name->data, rv,
                                      cf->conf_file->file.name.data,
                                      cf->conf_file->line);

                        rc = NGX_ERROR;
                        break;
                    }
                }

                cmd++;
            }
        }

        if (!found)
        {
            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                          "unknown directive \"%s\" in %s:%d",
                          name->data,
                          cf->conf_file->file.name.data,
                          cf->conf_file->line);

            rc = NGX_ERROR;
            break;
        }

        if (rc == NGX_ERROR)
        {
            break;
        }
    }

    if (filename)
    {
        cf->conf_file = prev;

        if (ngx_close_file(fd) == NGX_FILE_ERROR)
        {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          cf->conf_file->file.name.data);
            return NGX_CONF_ERROR;
        }
    }

    if (rc == NGX_ERROR)
    {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static ngx_int_t
ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
{
    ngx_fd_t         fd;
    ngx_file_info_t  fi;

    of->fd = NGX_INVALID_FILE;

    if (of->test_dir) {

        if (ngx_file_info(name, &fi) == -1) {
            of->err = ngx_errno;

            return NGX_ERROR;
        }

        of->uniq = ngx_file_uniq(&fi);
        of->mtime = ngx_file_mtime(&fi);
        of->size = ngx_file_size(&fi);
        of->is_dir = ngx_is_dir(&fi);
        of->is_file = ngx_is_file(&fi);
        of->is_link = ngx_is_link(&fi);
        of->is_exec = ngx_is_exec(&fi);

        if (of->is_dir) {
            return NGX_OK;
        }
    }

    fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

    if (fd == NGX_INVALID_FILE) {
        of->err = ngx_errno;
        return NGX_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", name);

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        return NGX_ERROR;
    }

    if (ngx_is_dir(&fi)) {
        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        fd = NGX_INVALID_FILE;
    }

    of->fd = fd;
    of->uniq = ngx_file_uniq(&fi);
    of->mtime = ngx_file_mtime(&fi);
    of->size = ngx_file_size(&fi);
    of->is_dir = ngx_is_dir(&fi);
    of->is_file = ngx_is_file(&fi);
    of->is_link = ngx_is_link(&fi);
    of->is_exec = ngx_is_exec(&fi);

    return NGX_OK;
}
Exemple #28
0
void
ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
{
    off_t                   size, length;
    ngx_int_t               rc;
    ngx_file_uniq_t         uniq;
    ngx_file_info_t         fi;
    ngx_http_cache_t        *c;
    ngx_ext_rename_file_t   ext;
    ngx_http_file_cache_t  *cache;

    c = r->cache;

    if (c->updated) {
        return;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache update");

    c->updated = 1;

    cache = c->file_cache;

    uniq = 0;
    length = 0;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http file cache rename: \"%s\" to \"%s\"",
                   tf->file.name.data, c->file.name.data);

    ext.access = NGX_FILE_OWNER_ACCESS;
    ext.path_access = NGX_FILE_OWNER_ACCESS;
    ext.time = -1;
    ext.create_path = 1;
    ext.delete_file = 1;
    ext.log = r->connection->log;

    rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);

    if (rc == NGX_OK) {

        if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", tf->file.name.data);

            rc = NGX_ERROR;

        } else {
            uniq = ngx_file_uniq(&fi);
            length = ngx_file_size(&fi);
        }
    }

    size = (length + cache->bsize - 1) / cache->bsize;

    ngx_shmtx_lock(&cache->shpool->mutex);

    c->node->count--;
    c->node->uniq = uniq;
    c->node->body_start = c->body_start;

    size = size - (c->node->length + cache->bsize - 1) / cache->bsize;

    c->node->length = length;

    cache->sh->size += size;

    if (rc == NGX_OK) {
        c->node->exists = 1;
    }

    c->node->updating = 0;

    ngx_shmtx_unlock(&cache->shpool->mutex);
}
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    u_char           *p;
    off_t             size;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf, *tbuf;
    ngx_conf_file_t  *prev, conf_file;
    ngx_conf_dump_t  *cd;
    enum {
        parse_file = 0,  //解析配置文件(初始配置文件解析)
        parse_block,  //解析配置文件中的块
        parse_param   //解析-g选项携带的参数
    } type;

#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif

    if (filename) {

        /* open configuration file */

        /*打开配置文件nginx.conf*/
        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
        if (fd == NGX_INVALID_FILE) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               ngx_open_file_n " \"%s\" failed",
                               filename->data);
            return NGX_CONF_ERROR;
        }

        /*保存之前的cf->conf_file*/
        prev = cf->conf_file;

        cf->conf_file = &conf_file;

        /*获取文件信息,如uid gid等*/
        if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
                          ngx_fd_info_n " \"%s\" failed", filename->data);
        }

        /*
         * 函数ngx_conf_read_token对配置文件内容逐个字符扫描并解析为单个的token,当然,该函数并不会频繁的去读取
         * 配置文件,它每次从文件内读取足够多的内容以填满一个大小为NGX_CONF_BUFFER的缓存区(除了最后一次,即配置
         * 文件剩余内容本来就不够了),这个缓存区在函数 ngx_conf_parse内申请并保存引用到变量cf->conf_file->buffer内,
         * 函数 ngx_conf_read_token反复使用该缓存区
         */

        /*构建cf->conf_file->buffer缓冲区*/
        cf->conf_file->buffer = &buf;

        buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
        if (buf.start == NULL) {
            goto failed;
        }

        buf.pos = buf.start;
        buf.last = buf.start;
        buf.end = buf.last + NGX_CONF_BUFFER;
        buf.temporary = 1;

        /*cf->conf_file指向当前配置文件/usr/local/nginx/conf/nginx.conf*/
        cf->conf_file->file.fd = fd;
        cf->conf_file->file.name.len = filename->len;
        cf->conf_file->file.name.data = filename->data;
        cf->conf_file->file.offset = 0;
        cf->conf_file->file.log = cf->log;
        cf->conf_file->line = 1;

        type = parse_file;

        /*复制一份配置文件*/
        if (ngx_dump_config
#if (NGX_DEBUG)
            || 1
#endif
           )
        {
            p = ngx_pstrdup(cf->cycle->pool, filename);
            if (p == NULL) {
                goto failed;
            }

            size = ngx_file_size(&cf->conf_file->file.info);

            tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
            if (tbuf == NULL) {
                goto failed;
            }

            cd = ngx_array_push(&cf->cycle->config_dump);
            if (cd == NULL) {
                goto failed;
            }

            cd->name.len = filename->len;
            cd->name.data = p;
            cd->buffer = tbuf;

            cf->conf_file->dump = tbuf;

        } else {
            cf->conf_file->dump = NULL;
        }

    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

        type = parse_block;

    } else {
        type = parse_param;
    }


    for ( ;; ) {
        /* 
         * 读取文件中的内容放到缓冲区中cf->conf_file->buffer,并进行解析,把解析的结果放到了cf->args 里面, 指令的每个单词都在数组中
         * 占一个位置,比如 set debug off  ,那么数组中存三个位置。
         */
        rc = ngx_conf_read_token(cf);

        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */

        if (rc == NGX_ERROR) {
            goto done;
        }

        /*NGX_CONF_BLOCK_DONE解析块结束*/
        if (rc == NGX_CONF_BLOCK_DONE) {

            if (type != parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_FILE_DONE) {

            if (type == parse_block) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "unexpected end of file, expecting \"}\"");
                goto failed;
            }

            goto done;
        }

        if (rc == NGX_CONF_BLOCK_START) {

            if (type == parse_param) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "block directives are not supported "
                                   "in -g option");
                goto failed;
            }
        }

        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

        if (cf->handler) {

            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */

            if (rc == NGX_CONF_BLOCK_START) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
                goto failed;
            }

            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }

            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

            goto failed;
        }


        rc = ngx_conf_handler(cf, rc);

        if (rc == NGX_ERROR) {
            goto failed;
        }
    }

failed:

    rc = NGX_ERROR;

done:

    /*解析结束,恢复环境,关闭文件,释放内存*/
    if (filename) {
        if (cf->conf_file->buffer->start) {
            ngx_free(cf->conf_file->buffer->start);
        }

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                          ngx_close_file_n " %s failed",
                          filename->data);
            rc = NGX_ERROR;
        }

        cf->conf_file = prev;
    }

    if (rc == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}