static ngx_int_t ngx_http_filter_cache_open(ngx_http_request_t *r)
{
    ngx_http_cache_t *c = NULL;
    ngx_http_filter_cache_ctx_t *ctx = NULL;
    ngx_int_t rc;
    unsigned  cached = r->cached;

    ctx = r->filter_cache;
    c = r->cache;
    r->cache = ctx->cache;
    rc = ngx_http_file_cache_open(r);
    r->cache = c;

    r->cached = cached;

    return rc;
}
ngx_int_t
ngx_http_file_cache_viewer(ngx_http_request_t *r)
{
    ngx_http_file_cache_t  *cache;
    ngx_http_cache_t       *c;

    switch (ngx_http_file_cache_open(r)) {
    case NGX_OK:
    case NGX_HTTP_CACHE_STALE:
#  if defined(nginx_version) \
      && ((nginx_version >= 8001) \
          || ((nginx_version < 8000) && (nginx_version >= 7060)))
    case NGX_HTTP_CACHE_UPDATING:
#  endif
        break;
    case NGX_DECLINED:
        break;
#  if (NGX_HAVE_FILE_AIO)
    case NGX_AGAIN:
        return NGX_AGAIN;
#  endif
    default:
        return NGX_ERROR;
    }
    
    c = r->cache;
    cache = c->file_cache;
    
    ngx_shmtx_lock(&cache->shpool->mutex);
    
    if (!c->node->exists && c->node->uses == 1) {
        c->min_uses = 1;
        ngx_shmtx_unlock(&cache->shpool->mutex);
        return NGX_DECLINED;
    }
   
    ngx_shmtx_unlock(&cache->shpool->mutex);

    return NGX_OK;
}
ngx_int_t
ngx_http_file_cache_purge(ngx_http_request_t *r)
{
    ngx_http_file_cache_t  *cache;
    ngx_http_cache_t       *c;

    switch (ngx_http_file_cache_open(r)) {
    case NGX_OK:
    case NGX_HTTP_CACHE_STALE:
#  if (nginx_version >= 8001) \
       || ((nginx_version < 8000) && (nginx_version >= 7060))
    case NGX_HTTP_CACHE_UPDATING:
#  endif
        break;
    case NGX_DECLINED:
        return NGX_DECLINED;
#  if (NGX_HAVE_FILE_AIO)
    case NGX_AGAIN:
        return NGX_AGAIN;
#  endif
    default:
        return NGX_ERROR;
    }

    c = r->cache;
    cache = c->file_cache;

    /*
     * delete file from disk but *keep* in-memory node,
     * because other requests might still point to it.
     */

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

    if (!c->node->exists) {
        /* race between concurrent purges, backoff */
        ngx_shmtx_unlock(&cache->shpool->mutex);
        return NGX_DECLINED;
    }

#  if (nginx_version >= 1000001)
    cache->sh->size -= c->node->fs_size;
    c->node->fs_size = 0;
#  else
    cache->sh->size -= (c->node->length + cache->bsize - 1) / cache->bsize;
    c->node->length = 0;
#  endif

    c->node->exists = 0;
#  if (nginx_version >= 8001) \
       || ((nginx_version < 8000) && (nginx_version >= 7060))
    c->node->updating = 0;
#  endif

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

    if (ngx_delete_file(c->file.name.data) == NGX_FILE_ERROR) {
        /* entry in error log is enough, don't notice client */
        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                      ngx_delete_file_n " \"%s\" failed", c->file.name.data);
    }

    /* file deleted from cache */
    return NGX_OK;
}
ngx_int_t
ngx_selective_cache_purge_file_cache_lookup_on_disk(ngx_http_request_t *r, ngx_http_file_cache_t *cache, ngx_str_t *cache_key, u_char *md5_key)
{
#if NGX_HTTP_CACHE
    ngx_http_cache_t  *c;
    ngx_str_t         *key;
    ngx_int_t          rc;

    c = r->cache;
    if ((c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t))) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_selective_cache_purge: could not alloc memory to ngx_http_cache_t structure");
        return NGX_ERROR;
    }

    ngx_memzero(c, sizeof(ngx_http_cache_t));

    rc = ngx_array_init(&c->keys, r->pool, 1, sizeof(ngx_str_t));
    if (rc != NGX_OK) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_selective_cache_purge: could not alloc memory to keys array");
        return NGX_ERROR;
    }

    key = ngx_array_push(&c->keys);
    if (key == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_selective_cache_purge: could not alloc memory to key item");
        return NGX_ERROR;
    }

    key->data = cache_key->data;
    key->len = cache_key->len;

    r->cache = c;
    c->body_start = ngx_pagesize;
    c->file_cache = cache;
    c->file.log = r->connection->log;

    ngx_crc32_init(c->crc32);
    ngx_crc32_update(&c->crc32, cache_key->data, cache_key->len);
    ngx_crc32_final(c->crc32);

    c->header_start = sizeof(ngx_http_file_cache_header_t) + NGX_HTTP_FILE_CACHE_KEY_LEN + cache_key->len + 1;

    ngx_memcpy(c->key, md5_key, NGX_HTTP_CACHE_KEY_LEN);

    switch (ngx_http_file_cache_open(r)) {
    case NGX_OK:
    case NGX_HTTP_CACHE_STALE:
    case NGX_HTTP_CACHE_UPDATING:
        return NGX_OK;
        break;
    case NGX_DECLINED:
        return NGX_DECLINED;
#  if (NGX_HAVE_FILE_AIO)
    case NGX_AGAIN:
        return NGX_AGAIN;
#  endif
    default:
        return NGX_ERROR;
    }
#else
    return NGX_OK;
#endif
}