upstream nginx-0.7.31
[nginx.git] / nginx / src / core / ngx_garbage_collector.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9
10
11
12 ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level)
13 {
14     int         rc;
15     u_char     *last;
16     size_t      len;
17     ngx_err_t   err;
18     ngx_str_t   fname, buf;
19     ngx_dir_t   dir;
20
21     buf.len = 0;
22 #if (NGX_SUPPRESS_WARN)
23     buf.data = NULL;
24     fname.data = NULL;
25 #endif
26
27     ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
28                    "gc dir \"%s\":%d", dname->data, dname->len);
29
30     if (ngx_open_dir(dname, &dir) == NGX_ERROR) {
31         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
32                       ngx_open_dir_n " \"%s\" failed", dname->data);
33         return NGX_ERROR;
34     }
35
36     for ( ;; ) {
37         ngx_set_errno(0);
38         if (ngx_read_dir(&dir) == NGX_ERROR) {
39             err = ngx_errno;
40
41             if (err != NGX_ENOMOREFILES) {
42                 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
43                               ngx_read_dir_n " \"%s\" failed", dname->data);
44                 rc = NGX_ERROR;
45
46             } else {
47                 rc = NGX_OK;
48             }
49
50             break;
51         }
52
53         len = ngx_de_namelen(&dir);
54
55         ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
56                       "gc name \"%s\":%d", ngx_de_name(&dir), len);
57
58         if (len == 1 && ngx_de_name(&dir)[0] == '.') {
59             continue;
60         }
61
62         if (len == 2
63             && ngx_de_name(&dir)[0] == '.'
64             && ngx_de_name(&dir)[1] == '.')
65         {
66             continue;
67         }
68
69         fname.len = dname->len + 1+ len;
70
71         if (fname.len + NGX_DIR_MASK_LEN > buf.len) {
72
73             if (buf.len) {
74                 ngx_free(buf.data);
75             }
76
77             buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN;
78
79             buf.data = ngx_alloc(buf.len + 1, ctx->log);
80             if (buf.data == NULL) {
81                 return NGX_ABORT;
82             }
83         }
84
85         last = ngx_cpymem(buf.data, dname->data, dname->len);
86         *last++ = '/';
87         ngx_memcpy(last, ngx_de_name(&dir), len + 1);
88         fname.data = buf.data;
89
90         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
91                        "gc path: \"%s\"", fname.data);
92
93         if (!dir.valid_info) {
94             if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
95                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
96                               ngx_de_info_n " \"%s\" failed", fname.data);
97                 continue;
98             }
99         }
100
101         if (ngx_de_is_dir(&dir)) {
102
103             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
104                            "gc enter dir \"%s\"", fname.data);
105
106             if (level == -1
107                    /* there can not be directory on the last level */
108                 || level == NGX_MAX_PATH_LEVEL
109                    /* an directory from the old path hierarchy */
110                 || len != ctx->path->level[level])
111             {
112                 if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) {
113                     return NGX_ABORT;
114                 }
115
116                 fname.data[fname.len] = '\0';
117
118                 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
119                               "delete old hierachy directory \"%s\"",
120                               fname.data);
121
122                 if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) {
123                     ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
124                                   ngx_delete_dir_n " \"%s\" failed",
125                                   fname.data);
126                 } else {
127                     ctx->deleted++;
128                     ctx->freed += ngx_de_size(&dir);
129                 }
130
131                 continue;
132             }
133
134             if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) {
135                 return NGX_ABORT;
136             }
137
138         } else if (ngx_de_is_file(&dir)) {
139
140             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
141                            "gc file \"%s\"", fname.data);
142
143             if (level == -1
144                 || (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0))
145             {
146                 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
147                     ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
148                                   ngx_delete_file_n " \"%s\" failed",
149                                   fname.data);
150                 } else {
151                     ctx->deleted++;
152                     ctx->freed += ngx_de_size(&dir);
153                 }
154
155                 continue;
156             }
157
158             if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) {
159                 return NGX_ABORT;
160             }
161
162         } else {
163             ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
164                           "the file \"%s\" has unknown type, deleting",
165                           fname.data);
166
167             if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
168                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
169                               ngx_delete_file_n " \"%s\" failed", fname.data);
170             } else {
171                 ctx->deleted++;
172                 ctx->freed += ngx_de_size(&dir);
173             }
174         }
175     }
176
177     if (buf.len) {
178         ngx_free(buf.data);
179     }
180
181     if (ngx_close_dir(&dir) == NGX_ERROR) {
182         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
183                       ngx_close_dir_n " \"%s\" failed", fname.data);
184     }
185
186     return rc;
187 }
188
189
190 ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
191                                              ngx_dir_t *dir)
192 {
193     /*
194      * We use mtime only and do not use atime because:
195      *    on NTFS access time has a resolution of 1 hour,
196      *    on NT FAT access time has a resolution of 1 day,
197      *    Unices have the mount option "noatime".
198      */
199
200     if (ngx_time() - ngx_de_mtime(dir) < 3600) {
201         return NGX_OK;
202     }
203
204     ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
205                   "delete the stale temporary file \"%s\"", name->data);
206
207     if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
208         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
209                       ngx_delete_file_n " \"%s\" failed", name->data);
210         return NGX_ERROR;
211     }
212
213     ctx->deleted++;
214     ctx->freed += ngx_de_size(dir);
215
216     return NGX_OK;
217 }