~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/core/ngx_file.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 
 10 
 11 static ngx_atomic_t   temp_number = 0;
 12 ngx_atomic_t         *ngx_temp_number = &temp_number;
 13 ngx_atomic_int_t      ngx_random_number = 123456;
 14 
 15 
 16 ssize_t
 17 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
 18 {
 19     ngx_int_t  rc;
 20 
 21     if (tf->file.fd == NGX_INVALID_FILE) {
 22         rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
 23                                   tf->persistent, tf->clean, tf->access);
 24 
 25         if (rc == NGX_ERROR || rc == NGX_AGAIN) {
 26             return rc;
 27         }
 28 
 29         if (tf->log_level) {
 30             ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
 31                           tf->warn, &tf->file.name);
 32         }
 33     }
 34 
 35     return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
 36 }
 37 
 38 
 39 ngx_int_t
 40 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
 41     ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
 42 {
 43     uint32_t                  n;
 44     ngx_err_t                 err;
 45     ngx_pool_cleanup_t       *cln;
 46     ngx_pool_cleanup_file_t  *clnf;
 47 
 48     file->name.len = path->name.len + 1 + path->len + 10;
 49 
 50     file->name.data = ngx_pnalloc(pool, file->name.len + 1);
 51     if (file->name.data == NULL) {
 52         return NGX_ERROR;
 53     }
 54 
 55 #if 0
 56     for (i = 0; i < file->name.len; i++) {
 57          file->name.data[i] = 'X';
 58     }
 59 #endif
 60 
 61     ngx_memcpy(file->name.data, path->name.data, path->name.len);
 62 
 63     n = (uint32_t) ngx_next_temp_number(0);
 64 
 65     cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
 66     if (cln == NULL) {
 67         return NGX_ERROR;
 68     }
 69 
 70     for ( ;; ) {
 71         (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len,
 72                            "%010uD%Z", n);
 73 
 74         ngx_create_hashed_filename(path, file->name.data, file->name.len);
 75 
 76         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
 77                        "hashed path: %s", file->name.data);
 78 
 79         file->fd = ngx_open_tempfile(file->name.data, persistent, access);
 80 
 81         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
 82                        "temp fd:%d", file->fd);
 83 
 84         if (file->fd != NGX_INVALID_FILE) {
 85 
 86             cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
 87             clnf = cln->data;
 88 
 89             clnf->fd = file->fd;
 90             clnf->name = file->name.data;
 91             clnf->log = pool->log;
 92 
 93             return NGX_OK;
 94         }
 95 
 96         err = ngx_errno;
 97 
 98         if (err == NGX_EEXIST) {
 99             n = (uint32_t) ngx_next_temp_number(1);
100             continue;
101         }
102 
103         if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
104             ngx_log_error(NGX_LOG_CRIT, file->log, err,
105                           ngx_open_tempfile_n " \"%s\" failed",
106                           file->name.data);
107             return NGX_ERROR;
108         }
109 
110         if (ngx_create_path(file, path) == NGX_ERROR) {
111             return NGX_ERROR;
112         }
113     }
114 }
115 
116 
117 void
118 ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
119 {
120     size_t      i, level;
121     ngx_uint_t  n;
122 
123     i = path->name.len + 1;
124 
125     file[path->name.len + path->len]  = '/';
126 
127     for (n = 0; n < 3; n++) {
128         level = path->level[n];
129 
130         if (level == 0) {
131             break;
132         }
133 
134         len -= level;
135         file[i - 1] = '/';
136         ngx_memcpy(&file[i], &file[len], level);
137         i += level + 1;
138     }
139 }
140 
141 
142 ngx_int_t
143 ngx_create_path(ngx_file_t *file, ngx_path_t *path)
144 {
145     size_t      pos;
146     ngx_err_t   err;
147     ngx_uint_t  i;
148 
149     pos = path->name.len;
150 
151     for (i = 0; i < 3; i++) {
152         if (path->level[i] == 0) {
153             break;
154         }
155 
156         pos += path->level[i] + 1;
157 
158         file->name.data[pos] = '\0';
159 
160         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
161                        "temp file: \"%s\"", file->name.data);
162 
163         if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
164             err = ngx_errno;
165             if (err != NGX_EEXIST) {
166                 ngx_log_error(NGX_LOG_CRIT, file->log, err,
167                               ngx_create_dir_n " \"%s\" failed",
168                               file->name.data);
169                 return NGX_ERROR;
170             }
171         }
172 
173         file->name.data[pos] = '/';
174     }
175 
176     return NGX_OK;
177 }
178 
179 
180 ngx_err_t
181 ngx_create_full_path(u_char *dir, ngx_uint_t access)
182 {
183     u_char     *p, ch;
184     ngx_err_t   err;
185 
186     err = 0;
187 
188 #if (NGX_WIN32)
189     p = dir + 3;
190 #else
191     p = dir + 1;
192 #endif
193 
194     for ( /* void */ ; *p; p++) {
195         ch = *p;
196 
197         if (ch != '/') {
198             continue;
199         }
200 
201         *p = '\0';
202 
203         if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
204             err = ngx_errno;
205 
206             switch (err) {
207             case NGX_EEXIST:
208                 err = 0;
209             case NGX_EACCES:
210                 break;
211 
212             default:
213                 return err;
214             }
215         }
216 
217         *p = '/';
218     }
219 
220     return err;
221 }
222 
223 
224 ngx_atomic_uint_t
225 ngx_next_temp_number(ngx_uint_t collision)
226 {
227     ngx_atomic_uint_t  n, add;
228 
229     add = collision ? ngx_random_number : 1;
230 
231     n = ngx_atomic_fetch_add(ngx_temp_number, add);
232 
233     return n + add;
234 }
235 
236 
237 char *
238 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
239 {
240     char  *p = conf;
241 
242     ssize_t      level;
243     ngx_str_t   *value;
244     ngx_uint_t   i, n;
245     ngx_path_t  *path, **slot;
246 
247     slot = (ngx_path_t **) (p + cmd->offset);
248 
249     if (*slot) {
250         return "is duplicate";
251     }
252 
253     path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
254     if (path == NULL) {
255         return NGX_CONF_ERROR;
256     }
257 
258     value = cf->args->elts;
259 
260     path->name = value[1];
261 
262     if (path->name.data[path->name.len - 1] == '/') {
263         path->name.len--;
264     }
265 
266     if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) {
267         return NULL;
268     }
269 
270     path->len = 0;
271     path->manager = NULL;
272     path->loader = NULL;
273     path->conf_file = cf->conf_file->file.name.data;
274     path->line = cf->conf_file->line;
275 
276     for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
277         level = ngx_atoi(value[n].data, value[n].len);
278         if (level == NGX_ERROR || level == 0) {
279             return "invalid value";
280         }
281 
282         path->level[i] = level;
283         path->len += level + 1;
284     }
285 
286     while (i < 3) {
287         path->level[i++] = 0;
288     }
289 
290     *slot = path;
291 
292     if (ngx_add_path(cf, slot) == NGX_ERROR) {
293         return NGX_CONF_ERROR;
294     }
295 
296     return NGX_CONF_OK;
297 }
298 
299 
300 char *
301 ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
302     ngx_path_init_t *init)
303 {
304     if (*path) {
305         return NGX_CONF_OK;
306     }
307 
308     if (prev) {
309         *path = prev;
310         return NGX_CONF_OK;
311     }
312 
313     *path = ngx_palloc(cf->pool, sizeof(ngx_path_t));
314     if (*path == NULL) {
315         return NGX_CONF_ERROR;
316     }
317 
318     (*path)->name = init->name;
319 
320     if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) {
321         return NGX_CONF_ERROR;
322     }
323 
324     (*path)->level[0] = init->level[0];
325     (*path)->level[1] = init->level[1];
326     (*path)->level[2] = init->level[2];
327 
328     (*path)->len = init->level[0] + (init->level[0] ? 1 : 0)
329                    + init->level[1] + (init->level[1] ? 1 : 0)
330                    + init->level[2] + (init->level[2] ? 1 : 0);
331 
332     (*path)->manager = NULL;
333     (*path)->loader = NULL;
334     (*path)->conf_file = NULL;
335 
336     if (ngx_add_path(cf, path) != NGX_OK) {
337         return NGX_CONF_ERROR;
338     }
339 
340     return NGX_CONF_OK;
341 }
342 
343 
344 char *
345 ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
346 {
347     char  *confp = conf;
348 
349     u_char      *p;
350     ngx_str_t   *value;
351     ngx_uint_t   i, right, shift, *access;
352 
353     access = (ngx_uint_t *) (confp + cmd->offset);
354 
355     if (*access != NGX_CONF_UNSET_UINT) {
356         return "is duplicate";
357     }
358 
359     value = cf->args->elts;
360 
361     *access = 0600;
362 
363     for (i = 1; i < cf->args->nelts; i++) {
364 
365         p = value[i].data;
366 
367         if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
368             shift = 6;
369             p += sizeof("user:") - 1;
370 
371         } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
372             shift = 3;
373             p += sizeof("group:") - 1;
374 
375         } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
376             shift = 0;
377             p += sizeof("all:") - 1;
378 
379         } else {
380             goto invalid;
381         }
382 
383         if (ngx_strcmp(p, "rw") == 0) {
384             right = 6;
385 
386         } else if (ngx_strcmp(p, "r") == 0) {
387             right = 4;
388 
389         } else {
390             goto invalid;
391         }
392 
393         *access |= right << shift;
394     }
395 
396     return NGX_CONF_OK;
397 
398 invalid:
399 
400     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\"", &value[i]);
401 
402     return NGX_CONF_ERROR;
403 }
404 
405 
406 ngx_int_t
407 ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
408 {
409     ngx_uint_t   i, n;
410     ngx_path_t  *path, **p;
411 
412     path = *slot;
413 
414     p = cf->cycle->pathes.elts;
415     for (i = 0; i < cf->cycle->pathes.nelts; i++) {
416         if (p[i]->name.len == path->name.len
417             && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
418         {
419             for (n = 0; n < 3; n++) {
420                 if (p[i]->level[n] != path->level[n]) {
421                     if (path->conf_file == NULL) {
422                         if (p[i]->conf_file == NULL) {
423                             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
424                                       "the default path name \"%V\" has "
425                                       "the same name as another default path, "
426                                       "but the different levels, you need to "
427                                       "redefine one of them in http section",
428                                       &p[i]->name);
429                             return NGX_ERROR;
430                         }
431 
432                         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
433                                       "the path name \"%V\" in %s:%ui has "
434                                       "the same name as default path, but "
435                                       "the different levels, you need to "
436                                       "define default path in http section",
437                                       &p[i]->name, p[i]->conf_file, p[i]->line);
438                         return NGX_ERROR;
439                     }
440 
441                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
442                                       "the same path name \"%V\" in %s:%ui "
443                                       "has the different levels than",
444                                       &p[i]->name, p[i]->conf_file, p[i]->line);
445                     return NGX_ERROR;
446                 }
447 
448                 if (p[i]->level[n] == 0) {
449                     break;
450                 }
451             }
452 
453             *slot = p[i];
454 
455             return NGX_OK;
456         }
457     }
458 
459     p = ngx_array_push(&cf->cycle->pathes);
460     if (p == NULL) {
461         return NGX_ERROR;
462     }
463 
464     *p = path;
465 
466     return NGX_OK;
467 }
468 
469 
470 ngx_int_t
471 ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user)
472 {
473     ngx_err_t         err;
474     ngx_uint_t        i;
475     ngx_path_t      **path;
476 
477     path = cycle->pathes.elts;
478     for (i = 0; i < cycle->pathes.nelts; i++) {
479 
480         if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
481             err = ngx_errno;
482             if (err != NGX_EEXIST) {
483                 ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
484                               ngx_create_dir_n " \"%s\" failed",
485                               path[i]->name.data);
486                 return NGX_ERROR;
487             }
488         }
489 
490         if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
491             continue;
492         }
493 
494 #if !(NGX_WIN32)
495         {
496         ngx_file_info_t   fi;
497 
498         if (ngx_file_info((const char *) path[i]->name.data, &fi)
499             == NGX_FILE_ERROR)
500         {
501             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
502                           ngx_file_info_n " \"%s\" failed", path[i]->name.data);
503             return NGX_ERROR;
504         }
505 
506         if (fi.st_uid != user) {
507             if (chown((const char *) path[i]->name.data, user, -1) == -1) {
508                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
509                               "chown(\"%s\", %d) failed",
510                               path[i]->name.data, user);
511                 return NGX_ERROR;
512             }
513         }
514 
515         if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
516                                                   != (S_IRUSR|S_IWUSR|S_IXUSR))
517         {
518             fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);
519 
520             if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
521                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
522                               "chmod() \"%s\" failed", path[i]->name.data);
523                 return NGX_ERROR;
524             }
525         }
526         }
527 #endif
528     }
529 
530     return NGX_OK;
531 }
532 
533 
534 ngx_int_t
535 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
536 {
537     u_char           *name;
538     ngx_err_t         err;
539     ngx_copy_file_t   cf;
540 
541 #if !(NGX_WIN32)
542 
543     if (ext->access) {
544         if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
545             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
546                           ngx_change_file_access_n " \"%s\" failed", src->data);
547             err = 0;
548             goto failed;
549         }
550     }
551 
552 #endif
553 
554     if (ext->time != -1) {
555         if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) {
556             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
557                           ngx_set_file_time_n " \"%s\" failed", src->data);
558             err = 0;
559             goto failed;
560         }
561     }
562 
563     if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
564         return NGX_OK;
565     }
566 
567     err = ngx_errno;
568 
569     if (err == NGX_ENOPATH) {
570 
571         if (!ext->create_path) {
572             goto failed;
573         }
574 
575         err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access));
576 
577         if (err) {
578             ngx_log_error(NGX_LOG_CRIT, ext->log, err,
579                           ngx_create_dir_n " \"%s\" failed", to->data);
580             err = 0;
581             goto failed;
582         }
583 
584         if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
585             return NGX_OK;
586         }
587 
588         err = ngx_errno;
589     }
590 
591 #if (NGX_WIN32)
592 
593     if (err == NGX_EEXIST) {
594         if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) {
595 
596             if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
597                 return NGX_OK;
598             }
599 
600             err = ngx_errno;
601 
602         } else {
603             err = 0;
604         }
605     }
606 
607 #endif
608 
609     if (err == NGX_EXDEV) {
610 
611         cf.size = -1;
612         cf.buf_size = 0;
613         cf.access = ext->access;
614         cf.time = ext->time;
615         cf.log = ext->log;
616 
617         name = ngx_alloc(to->len + 1 + 10 + 1, ext->log);
618         if (name == NULL) {
619             return NGX_ERROR;
620         }
621 
622         (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data,
623                            (uint32_t) ngx_next_temp_number(0));
624 
625         if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {
626 
627             if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) {
628                 ngx_free(name);
629 
630                 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
631                     ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
632                                   ngx_delete_file_n " \"%s\" failed",
633                                   src->data);
634                     return NGX_ERROR;
635                 }
636 
637                 return NGX_OK;
638             }
639 
640             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
641                           ngx_rename_file_n " \"%s\" to \"%s\" failed",
642                           name, to->data);
643 
644             if (ngx_delete_file(name) == NGX_FILE_ERROR) {
645                 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
646                               ngx_delete_file_n " \"%s\" failed", name);
647 
648             }
649         }
650 
651         ngx_free(name);
652 
653         err = 0;
654     }
655 
656 failed:
657 
658     if (ext->delete_file) {
659         if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
660             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
661                           ngx_delete_file_n " \"%s\" failed", src->data);
662         }
663     }
664 
665     if (err) {
666         ngx_log_error(NGX_LOG_CRIT, ext->log, err,
667                       ngx_rename_file_n " \"%s\" to \"%s\" failed",
668                       src->data, to->data);
669     }
670 
671     return NGX_ERROR;
672 }
673 
674 
675 ngx_int_t
676 ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
677 {
678     char             *buf;
679     off_t             size;
680     size_t            len;
681     ssize_t           n;
682     ngx_fd_t          fd, nfd;
683     ngx_int_t         rc;
684     ngx_file_info_t   fi;
685 
686     rc = NGX_ERROR;
687     buf = NULL;
688     nfd = NGX_INVALID_FILE;
689 
690     fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
691 
692     if (fd == NGX_INVALID_FILE) {
693         ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
694                       ngx_open_file_n " \"%s\" failed", from);
695         goto failed;
696     }
697 
698     if (cf->size != -1) {
699         size = cf->size;
700 
701     } else {
702         if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
703             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
704                           ngx_fd_info_n " \"%s\" failed", from);
705 
706             goto failed;
707         }
708 
709         size = ngx_file_size(&fi);
710     }
711 
712     len = cf->buf_size ? cf->buf_size : 65536;
713 
714     if ((off_t) len > size) {
715         len = (size_t) size;
716     }
717 
718     buf = ngx_alloc(len, cf->log);
719     if (buf == NULL) {
720         goto failed;
721     }
722 
723     nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
724                         cf->access);
725 
726     if (nfd == NGX_INVALID_FILE) {
727         ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
728                       ngx_open_file_n " \"%s\" failed", to);
729         goto failed;
730     }
731 
732     while (size > 0) {
733 
734         if ((off_t) len > size) {
735             len = (size_t) size;
736         }
737 
738         n = ngx_read_fd(fd, buf, len);
739 
740         if (n == NGX_FILE_ERROR) {
741             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
742                           ngx_read_fd_n " \"%s\" failed", from);
743             goto failed;
744         }
745 
746         if ((size_t) n != len) {
747             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
748                           ngx_read_fd_n " has read only %z of %uz from %s",
749                           n, size, from);
750             goto failed;
751         }
752 
753         n = ngx_write_fd(nfd, buf, len);
754 
755         if (n == NGX_FILE_ERROR) {
756             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
757                           ngx_write_fd_n " \"%s\" failed", to);
758             goto failed;
759         }
760 
761         if ((size_t) n != len) {
762             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
763                           ngx_write_fd_n " has written only %z of %uz to %s",
764                           n, size, to);
765             goto failed;
766         }
767 
768         size -= n;
769     }
770 
771     if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
772         ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
773                       ngx_set_file_time_n " \"%s\" failed", to);
774         goto failed;
775     }
776 
777     rc = NGX_OK;
778 
779 failed:
780 
781     if (nfd != NGX_INVALID_FILE) {
782         if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
783             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
784                           ngx_close_file_n " \"%s\" failed", to);
785         }
786     }
787 
788     if (fd != NGX_INVALID_FILE) {
789         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
790             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
791                           ngx_close_file_n " \"%s\" failed", from);
792         }
793     }
794 
795     if (buf) {
796         ngx_free(buf);
797     }
798 
799     return rc;
800 }
801 
802 
803 /*
804  * ctx->init_handler() - see ctx->alloc
805  * ctx->file_handler() - file handler
806  * ctx->pre_tree_handler() - handler is called before entering directory
807  * ctx->post_tree_handler() - handler is called after leaving directory
808  * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
809  *
810  * ctx->data - some data structure, it may be the same on all levels, or
811  *     reallocated if ctx->alloc is nonzero
812  *
813  * ctx->alloc - a size of data structure that is allocated at every level
814  *     and is initilialized by ctx->init_handler()
815  *
816  * ctx->log - a log
817  *
818  * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
819  */
820 
821 ngx_int_t
822 ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
823 {
824     void       *data, *prev;
825     u_char     *p, *name;
826     size_t      len;
827     ngx_int_t   rc;
828     ngx_err_t   err;
829     ngx_str_t   file, buf;
830     ngx_dir_t   dir;
831 
832     buf.len = 0;
833     buf.data = NULL;
834 
835     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
836                    "walk tree \"%V\"", tree);
837 
838     if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
839         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
840                       ngx_open_dir_n " \"%s\" failed", tree->data);
841         return NGX_ERROR;
842     }
843 
844     prev = ctx->data;
845 
846     if (ctx->alloc) {
847         data = ngx_alloc(ctx->alloc, ctx->log);
848         if (data == NULL) {
849             goto failed;
850         }
851 
852         if (ctx->init_handler(data, prev) == NGX_ABORT) {
853             goto failed;
854         }
855 
856         ctx->data = data;
857 
858     } else {
859         data = NULL;
860     }
861 
862     for ( ;; ) {
863 
864         ngx_set_errno(0);
865 
866         if (ngx_read_dir(&dir) == NGX_ERROR) {
867             err = ngx_errno;
868 
869             if (err == NGX_ENOMOREFILES) {
870                 rc = NGX_OK;
871 
872             } else {
873                 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
874                               ngx_read_dir_n " \"%s\" failed", tree->data);
875                 rc = NGX_ERROR;
876             }
877 
878             goto done;
879         }
880 
881         len = ngx_de_namelen(&dir);
882         name = ngx_de_name(&dir);
883 
884         ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
885                       "tree name %uz:\"%s\"", len, name);
886 
887         if (len == 1 && name[0] == '.') {
888             continue;
889         }
890 
891         if (len == 2 && name[0] == '.' && name[1] == '.') {
892             continue;
893         }
894 
895         file.len = tree->len + 1 + len;
896 
897         if (file.len + NGX_DIR_MASK_LEN > buf.len) {
898 
899             if (buf.len) {
900                 ngx_free(buf.data);
901             }
902 
903             buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
904 
905             buf.data = ngx_alloc(buf.len + 1, ctx->log);
906             if (buf.data == NULL) {
907                 goto failed;
908             }
909         }
910 
911         p = ngx_cpymem(buf.data, tree->data, tree->len);
912         *p++ = '/';
913         ngx_memcpy(p, name, len + 1);
914 
915         file.data = buf.data;
916 
917         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
918                        "tree path \"%s\"", file.data);
919 
920         if (!dir.valid_info) {
921             if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
922                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
923                               ngx_de_info_n " \"%s\" failed", file.data);
924                 continue;
925             }
926         }
927 
928         if (ngx_de_is_file(&dir)) {
929 
930             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
931                            "tree file \"%s\"", file.data);
932 
933             ctx->size = ngx_de_size(&dir);
934             ctx->access = ngx_de_access(&dir);
935             ctx->mtime = ngx_de_mtime(&dir);
936 
937             if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
938                 goto failed;
939             }
940 
941         } else if (ngx_de_is_dir(&dir)) {
942 
943             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
944                            "tree enter dir \"%s\"", file.data);
945 
946             ctx->access = ngx_de_access(&dir);
947             ctx->mtime = ngx_de_mtime(&dir);
948 
949             if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) {
950                 goto failed;
951             }
952 
953             if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
954                 goto failed;
955             }
956 
957             ctx->access = ngx_de_access(&dir);
958             ctx->mtime = ngx_de_mtime(&dir);
959 
960             if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
961                 goto failed;
962             }
963 
964         } else {
965 
966             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
967                            "tree special \"%s\"", file.data);
968 
969             if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
970                 goto failed;
971             }
972         }
973     }
974 
975 failed:
976 
977     rc = NGX_ABORT;
978 
979 done:
980 
981     if (buf.len) {
982         ngx_free(buf.data);
983     }
984 
985     if (data) {
986         ngx_free(data);
987         ctx->data = prev;
988     }
989 
990     if (ngx_close_dir(&dir) == NGX_ERROR) {
991         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
992                       ngx_close_dir_n " \"%s\" failed", tree->data);
993     }
994 
995     return rc;
996 }
997 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.