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); }
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; }
//这个函数的详细解析 //请参看: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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }