blob: ae6fab420a56e57a5959bfb60be279d7dec4451a [file] [log] [blame]
#include <ngx_config.h>
#include <ngx_core.h>
typedef struct ngx_gc_s ngx_gc_t;
typedef int (*ngx_gc_handler_pt) (ngx_gc_t *ctx, ngx_str_t *name,
ngx_file_info_t *fi);
struct ngx_gc_s {
ngx_path_t *path;
u_int deleted;
off_t freed;
ngx_gc_handler_pt handler;
ngx_log_t *log;
};
static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level);
#if 0
{
ngx_test_null(cycle->timer_events,
ngx_alloc(sizeof(ngx_event_t) * TIMERS, cycle->log),
NGX_ERROR);
ngx_event_timer_init(cycle);
}
void garbage_collector()
{
ngx_msec_t timer;
struct timeval tv;
ngx_epoch_msec_t delta;
for ( ;; ) {
timer = ngx_event_find_timer();
ngx_gettimeofday(&tv);
delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
msleep(timer);
ngx_gettimeofday(&tv);
ngx_cached_time = tv.tv_sec;
ngx_time_update();
delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
ngx_event_expire_timers((ngx_msec_t) delta);
}
}
#endif
void stub_init(ngx_log_t *log)
{
ngx_gc_t *ctx;
ngx_path_t path;
if (!(ctx = ngx_alloc(sizeof(ngx_gc_t), log))) {
return;
}
path.name.len = 4;
path.name.data = "temp";
path.len = 5;
path.level[0] = 1;
path.level[1] = 2;
path.level[2] = 0;
ctx->path = &path;
ctx->log = log;
ngx_collect_garbage(ctx, &path.name, 0);
}
static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level)
{
int nlen;
char *last;
ngx_str_t fname;
ngx_dir_t *dir;
ngx_dirent_t *de;
ngx_file_info_t fi;
fname.len = 0;
ngx_log_debug(ctx->log, "dir %s" _ dname->data);
dir = ngx_open_dir(dname->data);
if (dir == NULL) {
ngx_log_error(NGX_LOG_ERR, ctx->log, ngx_errno,
ngx_open_dir_n " \"%s\" failed", dname->data);
return NGX_ERROR;
}
for ( ;; ) {
de = ngx_read_dir(dir);
if (de == NULL) {
if (fname.len) {
ngx_free(fname.data);
}
break;
}
ngx_log_debug(ctx->log, "file %s" _ de->d_name);
#ifdef __FreeBSD__
nlen = de->d_namlen;
#else
nlen = ngx_strlen(de->d_name);
#endif
if (nlen == 1 && de->d_name[0] == '.') {
continue;
}
if (nlen == 2 && de->d_name[0] == '.' && de->d_name[1] == '.') {
continue;
}
if (dname->len + 1 + nlen > fname.len) {
if (fname.len) {
ngx_free(fname.data);
}
fname.len = dname->len + 1 + nlen;
if (!(fname.data = ngx_alloc(fname.len + 1, ctx->log))) {
return NGX_ABORT;
}
}
last = ngx_cpymem(fname.data, dname->data, dname->len);
*last++ = '/';
ngx_memcpy(last, de->d_name, nlen + 1);
ngx_log_debug(ctx->log, "de %s" _ fname.data);
if (ngx_file_type(fname.data, &fi) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_file_type_n " \"%s\" failed", fname.data);
continue;
}
if (ngx_is_dir((&fi))) {
ngx_log_debug(ctx->log, "enter %s" _ fname.data);
if (level == -1
/* there can not be directory on the last level */
|| level == NGX_MAX_PATH_LEVEL
/* an directory from the old path hierarchy */
|| nlen != ctx->path->level[level])
{
if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) {
return NGX_ABORT;
}
ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
"delete old hierachy directory \"%s\"",
fname.data);
if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_delete_dir_n " \"%s\" failed",
fname.data);
} else {
ctx->deleted++;
ctx->freed += ngx_file_size((&fi));
}
continue;
}
if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) {
return NGX_ABORT;
}
} else if (ngx_is_file((&fi))) {
if (level == -1
|| (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0))
{
if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed",
fname.data);
} else {
ctx->deleted++;
ctx->freed += ngx_file_size((&fi));
}
continue;
}
if (ctx->handler(ctx, &fname, &fi) == NGX_ABORT) {
return NGX_ABORT;
}
} else {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
"\"%s\" has unknown file type, deleting", fname.data);
if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed", fname.data);
} else {
ctx->deleted++;
ctx->freed += ngx_file_size((&fi));
}
}
}
return NGX_OK;
}
int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
ngx_file_info_t *fi)
{
/*
* we use mtime only and do not use atime because:
* on NTFS access time has a resolution of 1 hour,
* on NT FAT access time has a resolution of 1 day,
* Unices have mount option "noatime"
*/
if (ngx_cached_time - ngx_file_mtime(fi) < 3600) {
return NGX_OK;
}
ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
"delete stale temporary \"%s\"", name->data);
if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
ngx_delete_file_n " \"%s\" failed", name->data);
return NGX_ERROR;
}
ctx->deleted++;
ctx->freed += ngx_file_size(fi);
return NGX_OK;
}