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

Linux Cross Reference
Nginx/core/ngx_file.c

Version: ~ [ nginx-0.6.26 ] ~ [ nginx-0.5.35 ] ~ [ nginx-0.5.20 ] ~ [ nginx-0.5.19 ] ~

  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_uint_t  ngx_temp_number;
 12 static ngx_atomic_uint_t  ngx_random_number;
 13 
 14 
 15 ssize_t
 16 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
 17 {
 18     ngx_int_t  rc;
 19 
 20     if (tf->file.fd == NGX_INVALID_FILE) {
 21         rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
 22                                   tf->persistent, tf->clean, tf->access);
 23 
 24         if (rc == NGX_ERROR || rc == NGX_AGAIN) {
 25             return rc;
 26         }
 27 
 28         if (tf->log_level) {
 29             ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
 30                           tf->warn, &tf->file.name);
 31         }
 32     }
 33 
 34     return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
 35 }
 36 
 37 
 38 ngx_int_t
 39 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
 40     ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
 41 {
 42     uint32_t                  n;
 43     ngx_err_t                 err;
 44     ngx_pool_cleanup_t       *cln;
 45     ngx_pool_cleanup_file_t  *clnf;
 46 
 47     file->name.len = path->name.len + 1 + path->len + 10;
 48 
 49     file->name.data = ngx_palloc(pool, file->name.len + 1);
 50     if (file->name.data == NULL) {
 51         return NGX_ERROR;
 52     }
 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 
 62     n = (uint32_t) ngx_next_temp_number(0);
 63 
 64     cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
 65     if (cln == NULL) {
 66         return NGX_ERROR;
 67     }
 68 
 69     for ( ;; ) {
 70         (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len,
 71                            "%010uD%Z", n);
 72 
 73         ngx_create_hashed_filename(path, file->name.data, file->name.len);
 74 
 75         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
 76                        "hashed path: %s", file->name.data);
 77 
 78         file->fd = ngx_open_tempfile(file->name.data, persistent, access);
 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) {
 84 
 85             cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
 86             clnf = cln->data;
 87 
 88             clnf->fd = file->fd;
 89             clnf->name = file->name.data;
 90             clnf->log = pool->log;
 91 
 92             return NGX_OK;
 93         }
 94 
 95         err = ngx_errno;
 96 
 97         if (err == NGX_EEXIST) {
 98             n = (uint32_t) ngx_next_temp_number(1);
 99             continue;
100         }
101 
102         if ((path->level[0] == 0)
103             || (err != NGX_ENOENT
104 #if (NGX_WIN32)
105                 && err != NGX_ENOTDIR
106 #endif
107             ))
108         {
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 
122 void
123 ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
124 {
125     size_t      i, level;
126     ngx_uint_t  n;
127 
128     i = path->name.len + 1;
129 
130     file[path->name.len + path->len]  = '/';
131 
132     for (n = 0; n < 3; n++) {
133         level = path->level[n];
134 
135         if (level == 0) {
136             break;
137         }
138 
139         len -= level;
140         file[i - 1] = '/';
141         ngx_memcpy(&file[i], &file[len], level);
142         i += level + 1;
143     }
144 }
145 
146 
147 ngx_int_t
148 ngx_create_path(ngx_file_t *file, ngx_path_t *path)
149 {
150     size_t      pos;
151     ngx_err_t   err;
152     ngx_uint_t  i;
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 
168         if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
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 
185 ngx_err_t
186 ngx_create_full_path(u_char *dir, ngx_uint_t access)
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 
200         if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
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 
214 void
215 ngx_init_temp_number(void)
216 {
217     ngx_temp_number = 0;
218     ngx_random_number = 123456;
219 }
220 
221 
222 ngx_atomic_uint_t
223 ngx_next_temp_number(ngx_uint_t collision)
224 {
225     if (collision) {
226         ngx_temp_number += ngx_random_number;
227     }
228 
229     return ngx_temp_number++;
230 }
231 
232 
233 char *
234 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
235 {
236     char  *p = conf;
237 
238     ssize_t      level;
239     ngx_str_t   *value;
240     ngx_uint_t   i, n;
241     ngx_path_t  *path, **slot;
242 
243     slot = (ngx_path_t **) (p + cmd->offset);
244 
245     if (*slot) {
246         return "is duplicate";
247     }
248 
249     path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
250     if (path == NULL) {
251         return NGX_CONF_ERROR;
252     }
253 
254     value = cf->args->elts;
255 
256     path->name = value[1];
257 
258     if (path->name.data[path->name.len - 1] == '/') {
259         path->name.len--;
260     }
261 
262     if (ngx_conf_full_name(cf->cycle, &path->name, 0) == NGX_ERROR) {
263         return NULL;
264     }
265 
266     path->len = 0;
267     path->cleaner = (ngx_gc_handler_pt) cmd->post;
268     path->conf_file = cf->conf_file->file.name.data;
269     path->line = cf->conf_file->line;
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 
285     *slot = path;
286 
287     if (ngx_add_path(cf, slot) == NGX_ERROR) {
288         return NGX_CONF_ERROR;
289     }
290 
291     return NGX_CONF_OK;
292 }
293 
294 
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);
305 
306     if (*access != NGX_CONF_UNSET_UINT) {
307         return "is duplicate";
308     }
309 
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     }
346 
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 
357 ngx_int_t
358 ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
359 {
360     ngx_uint_t   i, n;
361     ngx_path_t  *path, **p;
362 
363     path = *slot;
364 
365     p = cf->cycle->pathes.elts;
366     for (i = 0; i < cf->cycle->pathes.nelts; i++) {
367         if (p[i]->name.len == path->name.len
368             && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
369         {
370             for (n = 0; n < 3; n++) {
371                 if (p[i]->level[n] != path->level[n]) {
372                     if (path->conf_file == NULL) {
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 
383                         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
384                                       "the path name \"%V\" in %s:%ui has "
385                                       "the same name as default path, but "
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 
392                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
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;
397                 }
398 
399                 if (p[i]->level[n] == 0) {
400                     break;
401                 }
402             }
403 
404             *slot = p[i];
405 
406             return NGX_OK;
407         }
408     }
409 
410     p = ngx_array_push(&cf->cycle->pathes);
411     if (p == NULL) {
412         return NGX_ERROR;
413     }
414 
415     *p = path;
416 
417     return NGX_OK;
418 }
419 
420 
421 ngx_int_t
422 ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user)
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 
431         if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
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 
441         if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
442             continue;
443         }
444 
445 #if !(NGX_WIN32)
446         {
447         ngx_file_info_t   fi;
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         }
475         }
476 #endif
477     }
478 
479     return NGX_OK;
480 }
481 
482 
483 ngx_int_t
484 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
485 {
486     ngx_err_t  err;
487 
488 #if !(NGX_WIN32)
489 
490     if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
491         ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
492                       ngx_change_file_access_n " \"%s\" failed", src->data);
493         err = 0;
494         goto failed;
495     }
496 
497 #endif
498 
499     if (ext->time != -1) {
500         if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) {
501             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
502                           ngx_set_file_time_n " \"%s\" failed", src->data);
503             err = 0;
504             goto failed;
505         }
506     }
507 
508     if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
509         return NGX_OK;
510     }
511 
512     err = ngx_errno;
513 
514     if (err == NGX_ENOENT) {
515 
516         if (!ext->create_path) {
517             goto failed;
518         }
519 
520         err = ngx_create_full_path(to->data, ngx_dir_access(ext->access));
521 
522         if (err) {
523             ngx_log_error(NGX_LOG_CRIT, ext->log, err,
524                           ngx_create_dir_n " \"%s\" failed", to->data);
525             err = 0;
526             goto failed;
527         }
528 
529         if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
530             return NGX_OK;
531         }
532 
533         err = ngx_errno;
534         goto failed;
535     }
536 
537 #if (NGX_WIN32)
538 
539     if (err == NGX_EEXIST) {
540         if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) {
541 
542             if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
543                 return NGX_OK;
544             }
545 
546             err = ngx_errno;
547 
548         } else {
549             err = 0;
550         }
551     }
552 
553 #endif
554 
555 failed:
556 
557     if (ext->delete) {
558         if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
559             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
560                           ngx_delete_file_n " \"%s\" failed", src->data);
561         }
562     }
563 
564     if (err) {
565         ngx_log_error(NGX_LOG_CRIT, ext->log, err,
566                       ngx_rename_file_n " \"%s\" to \"%s\" failed",
567                       src->data, to->data);
568     }
569 
570     return NGX_ERROR;
571 }
572 
573 
574 /*
575  * ctx->init_handler() - see ctx->alloc
576  * ctx->file_handler() - file handler
577  * ctx->pre_tree_handler() - handler is called before entering directory
578  * ctx->post_tree_handler() - handler is called after leaving directory
579  * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
580  *
581  * ctx->data - some data structure, it may be the same on all levels, or
582  *     reallocated if ctx->alloc is nonzero
583  *
584  * ctx->alloc - a size of data structure that is allocated at every level
585  *     and is initilialized by ctx->init_handler()
586  *
587  * ctx->log - a log
588  *
589  * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
590  */
591 
592 ngx_int_t
593 ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
594 {
595     void       *data, *prev;
596     u_char     *p, *name;
597     size_t      len;
598     ngx_int_t   rc;
599     ngx_err_t   err;
600     ngx_str_t   file, buf;
601     ngx_dir_t   dir;
602 
603     buf.len = 0;
604     buf.data = NULL;
605 
606     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
607                    "walk tree \"%V\"", tree);
608 
609     if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
610         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
611                       ngx_open_dir_n " \"%s\" failed", tree->data);
612         return NGX_ERROR;
613     }
614 
615     prev = ctx->data;
616 
617     if (ctx->alloc) {
618         data = ngx_alloc(ctx->alloc, ctx->log);
619         if (data == NULL) {
620             goto failed;
621         }
622 
623         if (ctx->init_handler(data, prev) == NGX_ABORT) {
624             goto failed;
625         }
626 
627         ctx->data = data;
628 
629     } else {
630         data = NULL;
631     }
632 
633     for ( ;; ) {
634 
635         ngx_set_errno(0);
636 
637         if (ngx_read_dir(&dir) == NGX_ERROR) {
638             err = ngx_errno;
639 
640             if (err == NGX_ENOMOREFILES) {
641                 rc = NGX_OK;
642 
643             } else {
644                 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
645                               ngx_read_dir_n " \"%s\" failed", tree->data);
646                 rc = NGX_ERROR;
647             }
648 
649             goto done;
650         }
651 
652         len = ngx_de_namelen(&dir);
653         name = ngx_de_name(&dir);
654 
655         ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
656                       "tree name %uz:\"%s\"", len, name);
657 
658         if (len == 1 && name[0] == '.') {
659             continue;
660         }
661 
662         if (len == 2 && name[0] == '.' && name[1] == '.') {
663             continue;
664         }
665 
666         file.len = tree->len + 1 + len;
667 
668         if (file.len + NGX_DIR_MASK_LEN > buf.len) {
669 
670             if (buf.len) {
671                 ngx_free(buf.data);
672             }
673 
674             buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
675 
676             buf.data = ngx_alloc(buf.len + 1, ctx->log);
677             if (buf.data == NULL) {
678                 goto failed;
679             }
680         }
681 
682         p = ngx_cpymem(buf.data, tree->data, tree->len);
683         *p++ = '/';
684         ngx_memcpy(p, name, len + 1);
685 
686         file.data = buf.data;
687 
688         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
689                        "tree path \"%s\"", file.data);
690 
691         if (!dir.valid_info) {
692             if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
693                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
694                               ngx_de_info_n " \"%s\" failed", file.data);
695                 continue;
696             }
697         }
698 
699         if (ngx_de_is_file(&dir)) {
700 
701             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
702                            "tree file \"%s\"", file.data);
703 
704             ctx->size = ngx_de_size(&dir);
705             ctx->access = ngx_de_access(&dir);
706             ctx->mtime = ngx_de_mtime(&dir);
707 
708             if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
709                 goto failed;
710             }
711 
712         } else if (ngx_de_is_dir(&dir)) {
713 
714             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
715                            "tree enter dir \"%s\"", file.data);
716 
717             ctx->access = ngx_de_access(&dir);
718             ctx->mtime = ngx_de_mtime(&dir);
719 
720             if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) {
721                 goto failed;
722             }
723 
724             if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
725                 goto failed;
726             }
727 
728             ctx->access = ngx_de_access(&dir);
729             ctx->mtime = ngx_de_mtime(&dir);
730 
731             if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
732                 goto failed;
733             }
734 
735         } else {
736 
737             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
738                            "tree special \"%s\"", file.data);
739 
740             if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
741                 goto failed;
742             }
743         }
744     }
745 
746 failed:
747 
748     rc = NGX_ABORT;
749 
750 done:
751 
752     if (buf.len) {
753         ngx_free(buf.data);
754     }
755 
756     if (data) {
757         ngx_free(data);
758         ctx->data = prev;
759     }
760 
761     if (ngx_close_dir(&dir) == NGX_ERROR) {
762         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
763                       ngx_close_dir_n " \"%s\" failed", tree->data);
764     }
765 
766     return rc;
767 }
768 

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