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

Linux Cross Reference
Nginx/core/ngx_file.c

Version: ~ [ nginx-1.4.1 ] ~ [ nginx-1.5.0 ] ~

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

~ [ 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.