0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9
|
|
10
|
44
|
11 static ngx_atomic_uint_t ngx_temp_number;
|
250
|
12 static ngx_atomic_uint_t ngx_random_number;
|
0
|
13
|
|
14
|
42
|
15 ssize_t
|
|
16 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
|
0
|
17 {
|
16
|
18 ngx_int_t rc;
|
0
|
19
|
|
20 if (tf->file.fd == NGX_INVALID_FILE) {
|
|
21 rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
|
278
|
22 tf->persistent, tf->clean, tf->access);
|
0
|
23
|
|
24 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
|
|
25 return rc;
|
|
26 }
|
|
27
|
216
|
28 if (tf->log_level) {
|
|
29 ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
|
186
|
30 tf->warn, &tf->file.name);
|
0
|
31 }
|
|
32 }
|
|
33
|
|
34 return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
|
|
35 }
|
|
36
|
|
37
|
42
|
38 ngx_int_t
|
|
39 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
|
278
|
40 ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
|
0
|
41 {
|
282
|
42 uint32_t n;
|
58
|
43 ngx_err_t err;
|
112
|
44 ngx_pool_cleanup_t *cln;
|
|
45 ngx_pool_cleanup_file_t *clnf;
|
0
|
46
|
282
|
47 file->name.len = path->name.len + 1 + path->len + 10;
|
0
|
48
|
50
|
49 file->name.data = ngx_palloc(pool, file->name.len + 1);
|
|
50 if (file->name.data == NULL) {
|
16
|
51 return NGX_ERROR;
|
|
52 }
|
0
|
53
|
|
54 #if 0
|
|
55 for (i = 0; i < file->name.len; i++) {
|
|
56 file->name.data[i] = 'X';
|
|
57 }
|
|
58 #endif
|
|
59
|
|
60 ngx_memcpy(file->name.data, path->name.data, path->name.len);
|
|
61
|
282
|
62 n = (uint32_t) ngx_next_temp_number(0);
|
0
|
63
|
356
|
64 cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
|
|
65 if (cln == NULL) {
|
|
66 return NGX_ERROR;
|
|
67 }
|
|
68
|
0
|
69 for ( ;; ) {
|
66
|
70 (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len,
|
282
|
71 "%010uD%Z", n);
|
0
|
72
|
356
|
73 ngx_create_hashed_filename(path, file->name.data, file->name.len);
|
0
|
74
|
356
|
75 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
76 "hashed path: %s", file->name.data);
|
112
|
77
|
276
|
78 file->fd = ngx_open_tempfile(file->name.data, persistent, access);
|
0
|
79
|
|
80 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
81 "temp fd:%d", file->fd);
|
|
82
|
|
83 if (file->fd != NGX_INVALID_FILE) {
|
112
|
84
|
278
|
85 cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
|
112
|
86 clnf = cln->data;
|
58
|
87
|
112
|
88 clnf->fd = file->fd;
|
|
89 clnf->name = file->name.data;
|
|
90 clnf->log = pool->log;
|
58
|
91
|
0
|
92 return NGX_OK;
|
|
93 }
|
|
94
|
|
95 err = ngx_errno;
|
|
96
|
|
97 if (err == NGX_EEXIST) {
|
282
|
98 n = (uint32_t) ngx_next_temp_number(1);
|
0
|
99 continue;
|
|
100 }
|
|
101
|
|
102 if ((path->level[0] == 0)
|
|
103 || (err != NGX_ENOENT
|
10
|
104 #if (NGX_WIN32)
|
0
|
105 && err != NGX_ENOTDIR
|
|
106 #endif
|
16
|
107 ))
|
|
108 {
|
0
|
109 ngx_log_error(NGX_LOG_CRIT, file->log, err,
|
|
110 ngx_open_tempfile_n " \"%s\" failed",
|
|
111 file->name.data);
|
|
112 return NGX_ERROR;
|
|
113 }
|
|
114
|
|
115 if (ngx_create_path(file, path) == NGX_ERROR) {
|
|
116 return NGX_ERROR;
|
|
117 }
|
|
118 }
|
|
119 }
|
|
120
|
|
121
|
42
|
122 void
|
356
|
123 ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
|
0
|
124 {
|
356
|
125 size_t i, level;
|
|
126 ngx_uint_t n;
|
0
|
127
|
356
|
128 i = path->name.len + 1;
|
0
|
129
|
356
|
130 file[path->name.len + path->len] = '/';
|
0
|
131
|
356
|
132 for (n = 0; n < 3; n++) {
|
|
133 level = path->level[n];
|
0
|
134
|
|
135 if (level == 0) {
|
|
136 break;
|
|
137 }
|
|
138
|
356
|
139 len -= level;
|
|
140 file[i - 1] = '/';
|
|
141 ngx_memcpy(&file[i], &file[len], level);
|
|
142 i += level + 1;
|
0
|
143 }
|
|
144 }
|
|
145
|
|
146
|
42
|
147 ngx_int_t
|
|
148 ngx_create_path(ngx_file_t *file, ngx_path_t *path)
|
0
|
149 {
|
66
|
150 size_t pos;
|
|
151 ngx_err_t err;
|
|
152 ngx_uint_t i;
|
0
|
153
|
|
154 pos = path->name.len;
|
|
155
|
|
156 for (i = 0; i < 3; i++) {
|
|
157 if (path->level[i] == 0) {
|
|
158 break;
|
|
159 }
|
|
160
|
|
161 pos += path->level[i] + 1;
|
|
162
|
|
163 file->name.data[pos] = '\0';
|
|
164
|
|
165 ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
166 "temp file: \"%s\"", file->name.data);
|
|
167
|
218
|
168 if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
|
0
|
169 err = ngx_errno;
|
|
170 if (err != NGX_EEXIST) {
|
|
171 ngx_log_error(NGX_LOG_CRIT, file->log, err,
|
|
172 ngx_create_dir_n " \"%s\" failed",
|
|
173 file->name.data);
|
|
174 return NGX_ERROR;
|
|
175 }
|
|
176 }
|
|
177
|
|
178 file->name.data[pos] = '/';
|
|
179 }
|
|
180
|
|
181 return NGX_OK;
|
|
182 }
|
|
183
|
|
184
|
186
|
185 ngx_err_t
|
218
|
186 ngx_create_full_path(u_char *dir, ngx_uint_t access)
|
186
|
187 {
|
|
188 u_char *p, ch;
|
|
189 ngx_err_t err;
|
|
190
|
|
191 for (p = dir + 1; *p; p++) {
|
|
192 ch = *p;
|
|
193
|
|
194 if (ch != '/') {
|
|
195 continue;
|
|
196 }
|
|
197
|
|
198 *p = '\0';
|
|
199
|
218
|
200 if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
|
186
|
201 err = ngx_errno;
|
|
202 if (err != NGX_EEXIST) {
|
|
203 return err;
|
|
204 }
|
|
205 }
|
|
206
|
|
207 *p = '/';
|
|
208 }
|
|
209
|
|
210 return 0;
|
|
211 }
|
|
212
|
|
213
|
42
|
214 void
|
48
|
215 ngx_init_temp_number(void)
|
0
|
216 {
|
42
|
217 ngx_temp_number = 0;
|
250
|
218 ngx_random_number = 123456;
|
0
|
219 }
|
|
220
|
|
221
|
44
|
222 ngx_atomic_uint_t
|
42
|
223 ngx_next_temp_number(ngx_uint_t collision)
|
0
|
224 {
|
|
225 if (collision) {
|
250
|
226 ngx_temp_number += ngx_random_number;
|
0
|
227 }
|
|
228
|
|
229 return ngx_temp_number++;
|
|
230 }
|
|
231
|
|
232
|
42
|
233 char *
|
|
234 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
0
|
235 {
|
|
236 char *p = conf;
|
|
237
|
16
|
238 ssize_t level;
|
178
|
239 ngx_str_t *value;
|
0
|
240 ngx_uint_t i, n;
|
28
|
241 ngx_path_t *path, **slot;
|
0
|
242
|
16
|
243 slot = (ngx_path_t **) (p + cmd->offset);
|
0
|
244
|
16
|
245 if (*slot) {
|
0
|
246 return "is duplicate";
|
|
247 }
|
|
248
|
50
|
249 path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
|
|
250 if (path == NULL) {
|
16
|
251 return NGX_CONF_ERROR;
|
|
252 }
|
0
|
253
|
16
|
254 value = cf->args->elts;
|
0
|
255
|
|
256 path->name = value[1];
|
178
|
257
|
210
|
258 if (path->name.data[path->name.len - 1] == '/') {
|
|
259 path->name.len--;
|
|
260 }
|
|
261
|
324
|
262 if (ngx_conf_full_name(cf->cycle, &path->name, 0) == NGX_ERROR) {
|
178
|
263 return NULL;
|
|
264 }
|
|
265
|
0
|
266 path->len = 0;
|
28
|
267 path->cleaner = (ngx_gc_handler_pt) cmd->post;
|
16
|
268 path->conf_file = cf->conf_file->file.name.data;
|
|
269 path->line = cf->conf_file->line;
|
0
|
270
|
|
271 for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
|
|
272 level = ngx_atoi(value[n].data, value[n].len);
|
|
273 if (level == NGX_ERROR || level == 0) {
|
|
274 return "invalid value";
|
|
275 }
|
|
276
|
|
277 path->level[i] = level;
|
|
278 path->len += level + 1;
|
|
279 }
|
|
280
|
|
281 while (i < 3) {
|
|
282 path->level[i++] = 0;
|
|
283 }
|
|
284
|
28
|
285 *slot = path;
|
16
|
286
|
28
|
287 if (ngx_add_path(cf, slot) == NGX_ERROR) {
|
|
288 return NGX_CONF_ERROR;
|
|
289 }
|
|
290
|
|
291 return NGX_CONF_OK;
|
|
292 }
|
|
293
|
|
294
|
318
|
295 char *
|
|
296 ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|
297 {
|
|
298 char *confp = conf;
|
|
299
|
|
300 u_char *p;
|
|
301 ngx_str_t *value;
|
|
302 ngx_uint_t i, right, shift, *access;
|
|
303
|
|
304 access = (ngx_uint_t *) (confp + cmd->offset);
|
320
|
305
|
318
|
306 if (*access != NGX_CONF_UNSET_UINT) {
|
|
307 return "is duplicate";
|
|
308 }
|
320
|
309
|
318
|
310 value = cf->args->elts;
|
|
311
|
|
312 *access = 0600;
|
|
313
|
|
314 for (i = 1; i < cf->args->nelts; i++) {
|
|
315
|
|
316 p = value[i].data;
|
|
317
|
|
318 if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
|
|
319 shift = 6;
|
|
320 p += sizeof("user:") - 1;
|
|
321
|
|
322 } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
|
|
323 shift = 3;
|
|
324 p += sizeof("group:") - 1;
|
|
325
|
|
326 } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
|
|
327 shift = 0;
|
|
328 p += sizeof("all:") - 1;
|
|
329
|
|
330 } else {
|
|
331 goto invalid;
|
|
332 }
|
|
333
|
|
334 if (ngx_strcmp(p, "rw") == 0) {
|
|
335 right = 6;
|
|
336
|
|
337 } else if (ngx_strcmp(p, "r") == 0) {
|
|
338 right = 4;
|
|
339
|
|
340 } else {
|
|
341 goto invalid;
|
|
342 }
|
|
343
|
|
344 *access |= right << shift;
|
|
345 }
|
320
|
346
|
318
|
347 return NGX_CONF_OK;
|
|
348
|
|
349 invalid:
|
|
350
|
|
351 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\"", &value[i]);
|
|
352
|
|
353 return NGX_CONF_ERROR;
|
|
354 }
|
|
355
|
|
356
|
42
|
357 ngx_int_t
|
|
358 ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
|
28
|
359 {
|
|
360 ngx_uint_t i, n;
|
|
361 ngx_path_t *path, **p;
|
|
362
|
|
363 path = *slot;
|
|
364
|
|
365 p = cf->cycle->pathes.elts;
|
16
|
366 for (i = 0; i < cf->cycle->pathes.nelts; i++) {
|
28
|
367 if (p[i]->name.len == path->name.len
|
|
368 && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
|
16
|
369 {
|
|
370 for (n = 0; n < 3; n++) {
|
28
|
371 if (p[i]->level[n] != path->level[n]) {
|
|
372 if (path->conf_file == NULL) {
|
30
|
373 if (p[i]->conf_file == NULL) {
|
|
374 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
|
375 "the default path name \"%V\" has "
|
|
376 "the same name as another default path, "
|
|
377 "but the different levels, you need to "
|
|
378 "redefine one of them in http section",
|
|
379 &p[i]->name);
|
|
380 return NGX_ERROR;
|
|
381 }
|
|
382
|
28
|
383 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
|
384 "the path name \"%V\" in %s:%ui has "
|
30
|
385 "the same name as default path, but "
|
28
|
386 "the different levels, you need to "
|
|
387 "define default path in http section",
|
|
388 &p[i]->name, p[i]->conf_file, p[i]->line);
|
|
389 return NGX_ERROR;
|
|
390 }
|
|
391
|
16
|
392 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
28
|
393 "the same path name \"%V\" in %s:%ui "
|
|
394 "has the different levels than",
|
|
395 &p[i]->name, p[i]->conf_file, p[i]->line);
|
|
396 return NGX_ERROR;
|
16
|
397 }
|
|
398
|
28
|
399 if (p[i]->level[n] == 0) {
|
16
|
400 break;
|
|
401 }
|
|
402 }
|
|
403
|
28
|
404 *slot = p[i];
|
16
|
405
|
28
|
406 return NGX_OK;
|
16
|
407 }
|
|
408 }
|
|
409
|
50
|
410 p = ngx_array_push(&cf->cycle->pathes);
|
|
411 if (p == NULL) {
|
28
|
412 return NGX_ERROR;
|
16
|
413 }
|
|
414
|
28
|
415 *p = path;
|
0
|
416
|
28
|
417 return NGX_OK;
|
0
|
418 }
|
16
|
419
|
|
420
|
42
|
421 ngx_int_t
|
|
422 ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user)
|
16
|
423 {
|
|
424 ngx_err_t err;
|
|
425 ngx_uint_t i;
|
|
426 ngx_path_t **path;
|
|
427
|
|
428 path = cycle->pathes.elts;
|
|
429 for (i = 0; i < cycle->pathes.nelts; i++) {
|
|
430
|
218
|
431 if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
|
16
|
432 err = ngx_errno;
|
|
433 if (err != NGX_EEXIST) {
|
|
434 ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
|
|
435 ngx_create_dir_n " \"%s\" failed",
|
|
436 path[i]->name.data);
|
|
437 return NGX_ERROR;
|
|
438 }
|
|
439 }
|
|
440
|
66
|
441 if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
|
16
|
442 continue;
|
|
443 }
|
|
444
|
|
445 #if !(NGX_WIN32)
|
356
|
446 {
|
|
447 ngx_file_info_t fi;
|
16
|
448
|
|
449 if (ngx_file_info((const char *) path[i]->name.data, &fi) == -1) {
|
|
450 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
|
451 ngx_file_info_n " \"%s\" failed", path[i]->name.data);
|
|
452 return NGX_ERROR;
|
|
453 }
|
|
454
|
|
455 if (fi.st_uid != user) {
|
|
456 if (chown((const char *) path[i]->name.data, user, -1) == -1) {
|
|
457 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
|
458 "chown(\"%s\", %d) failed",
|
|
459 path[i]->name.data, user);
|
|
460 return NGX_ERROR;
|
|
461 }
|
|
462 }
|
|
463
|
|
464 if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
|
|
465 != (S_IRUSR|S_IWUSR|S_IXUSR))
|
|
466 {
|
|
467 fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);
|
|
468
|
|
469 if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
|
|
470 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
|
471 "chmod() \"%s\" failed", path[i]->name.data);
|
|
472 return NGX_ERROR;
|
|
473 }
|
|
474 }
|
356
|
475 }
|
16
|
476 #endif
|
|
477 }
|
|
478
|
|
479 return NGX_OK;
|
|
480 }
|
272
|
481
|
|
482
|
|
483 ngx_int_t
|
356
|
484 ngx_create_path_and_rename_file(ngx_str_t *src, ngx_str_t *to,
|
|
485 ngx_uint_t access, ngx_uint_t full_path, ngx_uint_t delete, ngx_log_t *log)
|
|
486 {
|
|
487 ngx_err_t err;
|
|
488
|
|
489 #if !(NGX_WIN32)
|
|
490
|
|
491 if (ngx_change_file_access(src->data, access) == NGX_FILE_ERROR) {
|
|
492 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
|
|
493 ngx_change_file_access_n " \"%s\" failed", src->data);
|
|
494 err = 0;
|
|
495 goto failed;
|
|
496 }
|
|
497
|
|
498 #endif
|
|
499
|
|
500 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
|
|
501 return NGX_OK;
|
|
502 }
|
|
503
|
|
504 err = ngx_errno;
|
|
505
|
|
506 if (err == NGX_ENOENT) {
|
|
507
|
|
508 if (!full_path) {
|
|
509 goto failed;
|
|
510 }
|
|
511
|
|
512 err = ngx_create_full_path(to->data, ngx_dir_access(access));
|
|
513
|
|
514 if (err) {
|
|
515 ngx_log_error(NGX_LOG_CRIT, log, err,
|
|
516 ngx_create_dir_n " \"%s\" failed", to->data);
|
|
517 err = 0;
|
|
518 goto failed;
|
|
519 }
|
|
520
|
|
521 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
|
|
522 return NGX_OK;
|
|
523 }
|
|
524
|
|
525 err = ngx_errno;
|
|
526 goto failed;
|
|
527 }
|
|
528
|
|
529 #if (NGX_WIN32)
|
|
530
|
|
531 if (err == NGX_EEXIST) {
|
|
532 if (ngx_win32_rename_file(src, to, log) == NGX_OK) {
|
|
533
|
|
534 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
|
|
535 return NGX_OK;
|
|
536 }
|
|
537
|
|
538 err = ngx_errno;
|
|
539
|
|
540 } else {
|
|
541 err = 0;
|
|
542 }
|
|
543 }
|
|
544
|
|
545 #endif
|
|
546
|
|
547 failed:
|
|
548
|
|
549 if (delete) {
|
|
550 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
|
|
551 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
|
|
552 ngx_delete_file_n " \"%s\" failed", src->data);
|
|
553 }
|
|
554 }
|
|
555
|
|
556 if (err) {
|
|
557 ngx_log_error(NGX_LOG_CRIT, log, err,
|
|
558 ngx_rename_file_n " \"%s\" to \"%s\" failed",
|
|
559 src->data, to->data);
|
|
560 }
|
|
561
|
|
562 return NGX_ERROR;
|
|
563 }
|
|
564
|
|
565
|
|
566 /*
|
|
567 * ctx->init_handler() - see ctx->alloc
|
|
568 * ctx->file_handler() - file handler
|
|
569 * ctx->pre_tree_handler() - handler is called before entering directory
|
|
570 * ctx->post_tree_handler() - handler is called after leaving directory
|
|
571 * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
|
|
572 *
|
|
573 * ctx->data - some data structure, it may be the same on all levels, or
|
|
574 * reallocated if ctx->alloc is nonzero
|
|
575 *
|
|
576 * ctx->alloc - a size of data structure that is allocated at every level
|
|
577 * and is initilialized by ctx->init_handler()
|
|
578 *
|
|
579 * ctx->log - a log
|
|
580 *
|
|
581 * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
|
|
582 */
|
|
583
|
|
584 ngx_int_t
|
272
|
585 ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
|
|
586 {
|
|
587 void *data, *prev;
|
|
588 u_char *p, *name;
|
|
589 size_t len;
|
|
590 ngx_int_t rc;
|
|
591 ngx_err_t err;
|
|
592 ngx_str_t file, buf;
|
|
593 ngx_dir_t dir;
|
|
594
|
|
595 buf.len = 0;
|
|
596 buf.data = NULL;
|
|
597
|
|
598 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
599 "walk tree \"%V\"", tree);
|
|
600
|
|
601 if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
|
|
602 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
603 ngx_open_dir_n " \"%s\" failed", tree->data);
|
|
604 return NGX_ERROR;
|
|
605 }
|
|
606
|
|
607 prev = ctx->data;
|
|
608
|
276
|
609 if (ctx->alloc) {
|
|
610 data = ngx_alloc(ctx->alloc, ctx->log);
|
272
|
611 if (data == NULL) {
|
|
612 goto failed;
|
|
613 }
|
|
614
|
|
615 if (ctx->init_handler(data, prev) == NGX_ABORT) {
|
|
616 goto failed;
|
|
617 }
|
|
618
|
|
619 ctx->data = data;
|
322
|
620
|
|
621 } else {
|
|
622 data = NULL;
|
272
|
623 }
|
|
624
|
|
625 for ( ;; ) {
|
|
626
|
|
627 ngx_set_errno(0);
|
|
628
|
|
629 if (ngx_read_dir(&dir) == NGX_ERROR) {
|
|
630 err = ngx_errno;
|
|
631
|
|
632 if (err == NGX_ENOMOREFILES) {
|
|
633 rc = NGX_OK;
|
|
634
|
|
635 } else {
|
|
636 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
|
|
637 ngx_read_dir_n " \"%s\" failed", tree->data);
|
|
638 rc = NGX_ERROR;
|
|
639 }
|
|
640
|
|
641 goto done;
|
|
642 }
|
|
643
|
|
644 len = ngx_de_namelen(&dir);
|
|
645 name = ngx_de_name(&dir);
|
|
646
|
|
647 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
648 "tree name %uz:\"%s\"", len, name);
|
|
649
|
|
650 if (len == 1 && name[0] == '.') {
|
|
651 continue;
|
|
652 }
|
|
653
|
|
654 if (len == 2 && name[0] == '.' && name[1] == '.') {
|
|
655 continue;
|
|
656 }
|
|
657
|
|
658 file.len = tree->len + 1 + len;
|
|
659
|
|
660 if (file.len + NGX_DIR_MASK_LEN > buf.len) {
|
|
661
|
|
662 if (buf.len) {
|
|
663 ngx_free(buf.data);
|
|
664 }
|
|
665
|
|
666 buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
|
|
667
|
|
668 buf.data = ngx_alloc(buf.len + 1, ctx->log);
|
|
669 if (buf.data == NULL) {
|
|
670 goto failed;
|
|
671 }
|
|
672 }
|
|
673
|
|
674 p = ngx_cpymem(buf.data, tree->data, tree->len);
|
|
675 *p++ = '/';
|
|
676 ngx_memcpy(p, name, len + 1);
|
|
677
|
|
678 file.data = buf.data;
|
|
679
|
|
680 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
681 "tree path \"%s\"", file.data);
|
|
682
|
|
683 if (!dir.valid_info) {
|
|
684 if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
|
|
685 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
686 ngx_de_info_n " \"%s\" failed", file.data);
|
|
687 continue;
|
|
688 }
|
|
689 }
|
|
690
|
|
691 if (ngx_de_is_file(&dir)) {
|
|
692
|
|
693 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
694 "tree file \"%s\"", file.data);
|
|
695
|
276
|
696 ctx->size = ngx_de_size(&dir);
|
|
697 ctx->access = ngx_de_access(&dir);
|
|
698 ctx->mtime = ngx_de_mtime(&dir);
|
|
699
|
272
|
700 if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
|
|
701 goto failed;
|
|
702 }
|
|
703
|
|
704 } else if (ngx_de_is_dir(&dir)) {
|
|
705
|
|
706 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
707 "tree enter dir \"%s\"", file.data);
|
|
708
|
276
|
709 ctx->access = ngx_de_access(&dir);
|
|
710 ctx->mtime = ngx_de_mtime(&dir);
|
|
711
|
272
|
712 if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) {
|
|
713 goto failed;
|
|
714 }
|
|
715
|
|
716 if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
|
|
717 goto failed;
|
|
718 }
|
|
719
|
276
|
720 ctx->access = ngx_de_access(&dir);
|
|
721 ctx->mtime = ngx_de_mtime(&dir);
|
|
722
|
272
|
723 if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
|
|
724 goto failed;
|
|
725 }
|
|
726
|
|
727 } else {
|
|
728
|
|
729 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
730 "tree special \"%s\"", file.data);
|
|
731
|
|
732 if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
|
|
733 goto failed;
|
|
734 }
|
|
735 }
|
|
736 }
|
|
737
|
|
738 failed:
|
|
739
|
|
740 rc = NGX_ABORT;
|
|
741
|
|
742 done:
|
|
743
|
|
744 if (buf.len) {
|
|
745 ngx_free(buf.data);
|
|
746 }
|
|
747
|
322
|
748 if (data) {
|
|
749 ngx_free(data);
|
272
|
750 ctx->data = prev;
|
|
751 }
|
|
752
|
|
753 if (ngx_close_dir(&dir) == NGX_ERROR) {
|
|
754 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
755 ngx_close_dir_n " \"%s\" failed", tree->data);
|
|
756 }
|
|
757
|
|
758 return rc;
|
|
759 }
|