Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 
0011 
0012 static ngx_int_t ngx_test_full_name(ngx_str_t *name);
0013 
0014 
0015 static ngx_atomic_t   temp_number = 0;
0016 ngx_atomic_t         *ngx_temp_number = &temp_number;
0017 ngx_atomic_int_t      ngx_random_number = 123456;
0018 
0019 
0020 ngx_int_t
0021 ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name)
0022 {
0023     size_t      len;
0024     u_char     *p, *n;
0025     ngx_int_t   rc;
0026 
0027     rc = ngx_test_full_name(name);
0028 
0029     if (rc == NGX_OK) {
0030         return rc;
0031     }
0032 
0033     len = prefix->len;
0034 
0035 #if (NGX_WIN32)
0036 
0037     if (rc == 2) {
0038         len = rc;
0039     }
0040 
0041 #endif
0042 
0043     n = ngx_pnalloc(pool, len + name->len + 1);
0044     if (n == NULL) {
0045         return NGX_ERROR;
0046     }
0047 
0048     p = ngx_cpymem(n, prefix->data, len);
0049     ngx_cpystrn(p, name->data, name->len + 1);
0050 
0051     name->len += len;
0052     name->data = n;
0053 
0054     return NGX_OK;
0055 }
0056 
0057 
0058 static ngx_int_t
0059 ngx_test_full_name(ngx_str_t *name)
0060 {
0061 #if (NGX_WIN32)
0062     u_char  c0, c1;
0063 
0064     c0 = name->data[0];
0065 
0066     if (name->len < 2) {
0067         if (c0 == '/') {
0068             return 2;
0069         }
0070 
0071         return NGX_DECLINED;
0072     }
0073 
0074     c1 = name->data[1];
0075 
0076     if (c1 == ':') {
0077         c0 |= 0x20;
0078 
0079         if ((c0 >= 'a' && c0 <= 'z')) {
0080             return NGX_OK;
0081         }
0082 
0083         return NGX_DECLINED;
0084     }
0085 
0086     if (c1 == '/') {
0087         return NGX_OK;
0088     }
0089 
0090     if (c0 == '/') {
0091         return 2;
0092     }
0093 
0094     return NGX_DECLINED;
0095 
0096 #else
0097 
0098     if (name->data[0] == '/') {
0099         return NGX_OK;
0100     }
0101 
0102     return NGX_DECLINED;
0103 
0104 #endif
0105 }
0106 
0107 
0108 ssize_t
0109 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
0110 {
0111     ngx_int_t  rc;
0112 
0113     if (tf->file.fd == NGX_INVALID_FILE) {
0114         rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
0115                                   tf->persistent, tf->clean, tf->access);
0116 
0117         if (rc != NGX_OK) {
0118             return rc;
0119         }
0120 
0121         if (tf->log_level) {
0122             ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
0123                           tf->warn, &tf->file.name);
0124         }
0125     }
0126 
0127 #if (NGX_THREADS && NGX_HAVE_PWRITEV)
0128 
0129     if (tf->thread_write) {
0130         return ngx_thread_write_chain_to_file(&tf->file, chain, tf->offset,
0131                                               tf->pool);
0132     }
0133 
0134 #endif
0135 
0136     return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
0137 }
0138 
0139 
0140 ngx_int_t
0141 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
0142     ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
0143 {
0144     size_t                    levels;
0145     u_char                   *p;
0146     uint32_t                  n;
0147     ngx_err_t                 err;
0148     ngx_str_t                 name;
0149     ngx_uint_t                prefix;
0150     ngx_pool_cleanup_t       *cln;
0151     ngx_pool_cleanup_file_t  *clnf;
0152 
0153     if (file->name.len) {
0154         name = file->name;
0155         levels = 0;
0156         prefix = 1;
0157 
0158     } else {
0159         name = path->name;
0160         levels = path->len;
0161         prefix = 0;
0162     }
0163 
0164     file->name.len = name.len + 1 + levels + 10;
0165 
0166     file->name.data = ngx_pnalloc(pool, file->name.len + 1);
0167     if (file->name.data == NULL) {
0168         return NGX_ERROR;
0169     }
0170 
0171 #if 0
0172     for (i = 0; i < file->name.len; i++) {
0173         file->name.data[i] = 'X';
0174     }
0175 #endif
0176 
0177     p = ngx_cpymem(file->name.data, name.data, name.len);
0178 
0179     if (prefix) {
0180         *p = '.';
0181     }
0182 
0183     p += 1 + levels;
0184 
0185     n = (uint32_t) ngx_next_temp_number(0);
0186 
0187     cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
0188     if (cln == NULL) {
0189         return NGX_ERROR;
0190     }
0191 
0192     for ( ;; ) {
0193         (void) ngx_sprintf(p, "%010uD%Z", n);
0194 
0195         if (!prefix) {
0196             ngx_create_hashed_filename(path, file->name.data, file->name.len);
0197         }
0198 
0199         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
0200                        "hashed path: %s", file->name.data);
0201 
0202         file->fd = ngx_open_tempfile(file->name.data, persistent, access);
0203 
0204         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
0205                        "temp fd:%d", file->fd);
0206 
0207         if (file->fd != NGX_INVALID_FILE) {
0208 
0209             cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
0210             clnf = cln->data;
0211 
0212             clnf->fd = file->fd;
0213             clnf->name = file->name.data;
0214             clnf->log = pool->log;
0215 
0216             return NGX_OK;
0217         }
0218 
0219         err = ngx_errno;
0220 
0221         if (err == NGX_EEXIST_FILE) {
0222             n = (uint32_t) ngx_next_temp_number(1);
0223             continue;
0224         }
0225 
0226         if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
0227             ngx_log_error(NGX_LOG_CRIT, file->log, err,
0228                           ngx_open_tempfile_n " \"%s\" failed",
0229                           file->name.data);
0230             return NGX_ERROR;
0231         }
0232 
0233         if (ngx_create_path(file, path) == NGX_ERROR) {
0234             return NGX_ERROR;
0235         }
0236     }
0237 }
0238 
0239 
0240 void
0241 ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
0242 {
0243     size_t      i, level;
0244     ngx_uint_t  n;
0245 
0246     i = path->name.len + 1;
0247 
0248     file[path->name.len + path->len]  = '/';
0249 
0250     for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) {
0251         level = path->level[n];
0252 
0253         if (level == 0) {
0254             break;
0255         }
0256 
0257         len -= level;
0258         file[i - 1] = '/';
0259         ngx_memcpy(&file[i], &file[len], level);
0260         i += level + 1;
0261     }
0262 }
0263 
0264 
0265 ngx_int_t
0266 ngx_create_path(ngx_file_t *file, ngx_path_t *path)
0267 {
0268     size_t      pos;
0269     ngx_err_t   err;
0270     ngx_uint_t  i;
0271 
0272     pos = path->name.len;
0273 
0274     for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) {
0275         if (path->level[i] == 0) {
0276             break;
0277         }
0278 
0279         pos += path->level[i] + 1;
0280 
0281         file->name.data[pos] = '\0';
0282 
0283         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
0284                        "temp file: \"%s\"", file->name.data);
0285 
0286         if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
0287             err = ngx_errno;
0288             if (err != NGX_EEXIST) {
0289                 ngx_log_error(NGX_LOG_CRIT, file->log, err,
0290                               ngx_create_dir_n " \"%s\" failed",
0291                               file->name.data);
0292                 return NGX_ERROR;
0293             }
0294         }
0295 
0296         file->name.data[pos] = '/';
0297     }
0298 
0299     return NGX_OK;
0300 }
0301 
0302 
0303 ngx_err_t
0304 ngx_create_full_path(u_char *dir, ngx_uint_t access)
0305 {
0306     u_char     *p, ch;
0307     ngx_err_t   err;
0308 
0309     err = 0;
0310 
0311 #if (NGX_WIN32)
0312     p = dir + 3;
0313 #else
0314     p = dir + 1;
0315 #endif
0316 
0317     for ( /* void */ ; *p; p++) {
0318         ch = *p;
0319 
0320         if (ch != '/') {
0321             continue;
0322         }
0323 
0324         *p = '\0';
0325 
0326         if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
0327             err = ngx_errno;
0328 
0329             switch (err) {
0330             case NGX_EEXIST:
0331                 err = 0;
0332             case NGX_EACCES:
0333                 break;
0334 
0335             default:
0336                 return err;
0337             }
0338         }
0339 
0340         *p = '/';
0341     }
0342 
0343     return err;
0344 }
0345 
0346 
0347 ngx_atomic_uint_t
0348 ngx_next_temp_number(ngx_uint_t collision)
0349 {
0350     ngx_atomic_uint_t  n, add;
0351 
0352     add = collision ? ngx_random_number : 1;
0353 
0354     n = ngx_atomic_fetch_add(ngx_temp_number, add);
0355 
0356     return n + add;
0357 }
0358 
0359 
0360 char *
0361 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0362 {
0363     char  *p = conf;
0364 
0365     ssize_t      level;
0366     ngx_str_t   *value;
0367     ngx_uint_t   i, n;
0368     ngx_path_t  *path, **slot;
0369 
0370     slot = (ngx_path_t **) (p + cmd->offset);
0371 
0372     if (*slot) {
0373         return "is duplicate";
0374     }
0375 
0376     path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
0377     if (path == NULL) {
0378         return NGX_CONF_ERROR;
0379     }
0380 
0381     value = cf->args->elts;
0382 
0383     path->name = value[1];
0384 
0385     if (path->name.data[path->name.len - 1] == '/') {
0386         path->name.len--;
0387     }
0388 
0389     if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) {
0390         return NGX_CONF_ERROR;
0391     }
0392 
0393     path->conf_file = cf->conf_file->file.name.data;
0394     path->line = cf->conf_file->line;
0395 
0396     for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
0397         level = ngx_atoi(value[n].data, value[n].len);
0398         if (level == NGX_ERROR || level == 0) {
0399             return "invalid value";
0400         }
0401 
0402         path->level[i] = level;
0403         path->len += level + 1;
0404     }
0405 
0406     if (path->len > 10 + i) {
0407         return "invalid value";
0408     }
0409 
0410     *slot = path;
0411 
0412     if (ngx_add_path(cf, slot) == NGX_ERROR) {
0413         return NGX_CONF_ERROR;
0414     }
0415 
0416     return NGX_CONF_OK;
0417 }
0418 
0419 
0420 char *
0421 ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
0422     ngx_path_init_t *init)
0423 {
0424     ngx_uint_t  i;
0425 
0426     if (*path) {
0427         return NGX_CONF_OK;
0428     }
0429 
0430     if (prev) {
0431         *path = prev;
0432         return NGX_CONF_OK;
0433     }
0434 
0435     *path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
0436     if (*path == NULL) {
0437         return NGX_CONF_ERROR;
0438     }
0439 
0440     (*path)->name = init->name;
0441 
0442     if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) {
0443         return NGX_CONF_ERROR;
0444     }
0445 
0446     for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) {
0447         (*path)->level[i] = init->level[i];
0448         (*path)->len += init->level[i] + (init->level[i] ? 1 : 0);
0449     }
0450 
0451     if (ngx_add_path(cf, path) != NGX_OK) {
0452         return NGX_CONF_ERROR;
0453     }
0454 
0455     return NGX_CONF_OK;
0456 }
0457 
0458 
0459 char *
0460 ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0461 {
0462     char  *confp = conf;
0463 
0464     u_char      *p;
0465     ngx_str_t   *value;
0466     ngx_uint_t   i, right, shift, *access, user;
0467 
0468     access = (ngx_uint_t *) (confp + cmd->offset);
0469 
0470     if (*access != NGX_CONF_UNSET_UINT) {
0471         return "is duplicate";
0472     }
0473 
0474     value = cf->args->elts;
0475 
0476     *access = 0;
0477     user = 0600;
0478 
0479     for (i = 1; i < cf->args->nelts; i++) {
0480 
0481         p = value[i].data;
0482 
0483         if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
0484             shift = 6;
0485             p += sizeof("user:") - 1;
0486             user = 0;
0487 
0488         } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
0489             shift = 3;
0490             p += sizeof("group:") - 1;
0491 
0492         } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
0493             shift = 0;
0494             p += sizeof("all:") - 1;
0495 
0496         } else {
0497             goto invalid;
0498         }
0499 
0500         if (ngx_strcmp(p, "rw") == 0) {
0501             right = 6;
0502 
0503         } else if (ngx_strcmp(p, "r") == 0) {
0504             right = 4;
0505 
0506         } else {
0507             goto invalid;
0508         }
0509 
0510         *access |= right << shift;
0511     }
0512 
0513     *access |= user;
0514 
0515     return NGX_CONF_OK;
0516 
0517 invalid:
0518 
0519     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\"", &value[i]);
0520 
0521     return NGX_CONF_ERROR;
0522 }
0523 
0524 
0525 ngx_int_t
0526 ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
0527 {
0528     ngx_uint_t   i, n;
0529     ngx_path_t  *path, **p;
0530 
0531     path = *slot;
0532 
0533     p = cf->cycle->paths.elts;
0534     for (i = 0; i < cf->cycle->paths.nelts; i++) {
0535         if (p[i]->name.len == path->name.len
0536             && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
0537         {
0538             if (p[i]->data != path->data) {
0539                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0540                                    "the same path name \"%V\" "
0541                                    "used in %s:%ui and",
0542                                    &p[i]->name, p[i]->conf_file, p[i]->line);
0543                 return NGX_ERROR;
0544             }
0545 
0546             for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) {
0547                 if (p[i]->level[n] != path->level[n]) {
0548                     if (path->conf_file == NULL) {
0549                         if (p[i]->conf_file == NULL) {
0550                             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0551                                       "the default path name \"%V\" has "
0552                                       "the same name as another default path, "
0553                                       "but the different levels, you need to "
0554                                       "redefine one of them in http section",
0555                                       &p[i]->name);
0556                             return NGX_ERROR;
0557                         }
0558 
0559                         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0560                                       "the path name \"%V\" in %s:%ui has "
0561                                       "the same name as default path, but "
0562                                       "the different levels, you need to "
0563                                       "define default path in http section",
0564                                       &p[i]->name, p[i]->conf_file, p[i]->line);
0565                         return NGX_ERROR;
0566                     }
0567 
0568                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0569                                       "the same path name \"%V\" in %s:%ui "
0570                                       "has the different levels than",
0571                                       &p[i]->name, p[i]->conf_file, p[i]->line);
0572                     return NGX_ERROR;
0573                 }
0574 
0575                 if (p[i]->level[n] == 0) {
0576                     break;
0577                 }
0578             }
0579 
0580             *slot = p[i];
0581 
0582             return NGX_OK;
0583         }
0584     }
0585 
0586     p = ngx_array_push(&cf->cycle->paths);
0587     if (p == NULL) {
0588         return NGX_ERROR;
0589     }
0590 
0591     *p = path;
0592 
0593     return NGX_OK;
0594 }
0595 
0596 
0597 ngx_int_t
0598 ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user)
0599 {
0600     ngx_err_t         err;
0601     ngx_uint_t        i;
0602     ngx_path_t      **path;
0603 
0604     path = cycle->paths.elts;
0605     for (i = 0; i < cycle->paths.nelts; i++) {
0606 
0607         if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
0608             err = ngx_errno;
0609             if (err != NGX_EEXIST) {
0610                 ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
0611                               ngx_create_dir_n " \"%s\" failed",
0612                               path[i]->name.data);
0613                 return NGX_ERROR;
0614             }
0615         }
0616 
0617         if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
0618             continue;
0619         }
0620 
0621 #if !(NGX_WIN32)
0622         {
0623         ngx_file_info_t   fi;
0624 
0625         if (ngx_file_info(path[i]->name.data, &fi) == NGX_FILE_ERROR) {
0626             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0627                           ngx_file_info_n " \"%s\" failed", path[i]->name.data);
0628             return NGX_ERROR;
0629         }
0630 
0631         if (fi.st_uid != user) {
0632             if (chown((const char *) path[i]->name.data, user, -1) == -1) {
0633                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0634                               "chown(\"%s\", %d) failed",
0635                               path[i]->name.data, user);
0636                 return NGX_ERROR;
0637             }
0638         }
0639 
0640         if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
0641                                                   != (S_IRUSR|S_IWUSR|S_IXUSR))
0642         {
0643             fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);
0644 
0645             if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
0646                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0647                               "chmod() \"%s\" failed", path[i]->name.data);
0648                 return NGX_ERROR;
0649             }
0650         }
0651         }
0652 #endif
0653     }
0654 
0655     return NGX_OK;
0656 }
0657 
0658 
0659 ngx_int_t
0660 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
0661 {
0662     u_char           *name;
0663     ngx_err_t         err;
0664     ngx_copy_file_t   cf;
0665 
0666 #if !(NGX_WIN32)
0667 
0668     if (ext->access) {
0669         if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
0670             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0671                           ngx_change_file_access_n " \"%s\" failed", src->data);
0672             err = 0;
0673             goto failed;
0674         }
0675     }
0676 
0677 #endif
0678 
0679     if (ext->time != -1) {
0680         if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) {
0681             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0682                           ngx_set_file_time_n " \"%s\" failed", src->data);
0683             err = 0;
0684             goto failed;
0685         }
0686     }
0687 
0688     if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
0689         return NGX_OK;
0690     }
0691 
0692     err = ngx_errno;
0693 
0694     if (err == NGX_ENOPATH) {
0695 
0696         if (!ext->create_path) {
0697             goto failed;
0698         }
0699 
0700         err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access));
0701 
0702         if (err) {
0703             ngx_log_error(NGX_LOG_CRIT, ext->log, err,
0704                           ngx_create_dir_n " \"%s\" failed", to->data);
0705             err = 0;
0706             goto failed;
0707         }
0708 
0709         if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
0710             return NGX_OK;
0711         }
0712 
0713         err = ngx_errno;
0714     }
0715 
0716 #if (NGX_WIN32)
0717 
0718     if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) {
0719         err = ngx_win32_rename_file(src, to, ext->log);
0720 
0721         if (err == 0) {
0722             return NGX_OK;
0723         }
0724     }
0725 
0726 #endif
0727 
0728     if (err == NGX_EXDEV) {
0729 
0730         cf.size = -1;
0731         cf.buf_size = 0;
0732         cf.access = ext->access;
0733         cf.time = ext->time;
0734         cf.log = ext->log;
0735 
0736         name = ngx_alloc(to->len + 1 + 10 + 1, ext->log);
0737         if (name == NULL) {
0738             return NGX_ERROR;
0739         }
0740 
0741         (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data,
0742                            (uint32_t) ngx_next_temp_number(0));
0743 
0744         if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {
0745 
0746             if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) {
0747                 ngx_free(name);
0748 
0749                 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
0750                     ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0751                                   ngx_delete_file_n " \"%s\" failed",
0752                                   src->data);
0753                     return NGX_ERROR;
0754                 }
0755 
0756                 return NGX_OK;
0757             }
0758 
0759             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0760                           ngx_rename_file_n " \"%s\" to \"%s\" failed",
0761                           name, to->data);
0762 
0763             if (ngx_delete_file(name) == NGX_FILE_ERROR) {
0764                 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0765                               ngx_delete_file_n " \"%s\" failed", name);
0766 
0767             }
0768         }
0769 
0770         ngx_free(name);
0771 
0772         err = 0;
0773     }
0774 
0775 failed:
0776 
0777     if (ext->delete_file) {
0778         if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
0779             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0780                           ngx_delete_file_n " \"%s\" failed", src->data);
0781         }
0782     }
0783 
0784     if (err) {
0785         ngx_log_error(NGX_LOG_CRIT, ext->log, err,
0786                       ngx_rename_file_n " \"%s\" to \"%s\" failed",
0787                       src->data, to->data);
0788     }
0789 
0790     return NGX_ERROR;
0791 }
0792 
0793 
0794 ngx_int_t
0795 ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
0796 {
0797     char             *buf;
0798     off_t             size;
0799     size_t            len;
0800     ssize_t           n;
0801     ngx_fd_t          fd, nfd;
0802     ngx_int_t         rc;
0803     ngx_file_info_t   fi;
0804 
0805     rc = NGX_ERROR;
0806     buf = NULL;
0807     nfd = NGX_INVALID_FILE;
0808 
0809     fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
0810 
0811     if (fd == NGX_INVALID_FILE) {
0812         ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
0813                       ngx_open_file_n " \"%s\" failed", from);
0814         goto failed;
0815     }
0816 
0817     if (cf->size != -1) {
0818         size = cf->size;
0819 
0820     } else {
0821         if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
0822             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0823                           ngx_fd_info_n " \"%s\" failed", from);
0824 
0825             goto failed;
0826         }
0827 
0828         size = ngx_file_size(&fi);
0829     }
0830 
0831     len = cf->buf_size ? cf->buf_size : 65536;
0832 
0833     if ((off_t) len > size) {
0834         len = (size_t) size;
0835     }
0836 
0837     buf = ngx_alloc(len, cf->log);
0838     if (buf == NULL) {
0839         goto failed;
0840     }
0841 
0842     nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
0843                         cf->access);
0844 
0845     if (nfd == NGX_INVALID_FILE) {
0846         ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
0847                       ngx_open_file_n " \"%s\" failed", to);
0848         goto failed;
0849     }
0850 
0851     while (size > 0) {
0852 
0853         if ((off_t) len > size) {
0854             len = (size_t) size;
0855         }
0856 
0857         n = ngx_read_fd(fd, buf, len);
0858 
0859         if (n == -1) {
0860             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0861                           ngx_read_fd_n " \"%s\" failed", from);
0862             goto failed;
0863         }
0864 
0865         if ((size_t) n != len) {
0866             ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
0867                           ngx_read_fd_n " has read only %z of %O from %s",
0868                           n, size, from);
0869             goto failed;
0870         }
0871 
0872         n = ngx_write_fd(nfd, buf, len);
0873 
0874         if (n == -1) {
0875             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0876                           ngx_write_fd_n " \"%s\" failed", to);
0877             goto failed;
0878         }
0879 
0880         if ((size_t) n != len) {
0881             ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
0882                           ngx_write_fd_n " has written only %z of %O to %s",
0883                           n, size, to);
0884             goto failed;
0885         }
0886 
0887         size -= n;
0888     }
0889 
0890     if (cf->time != -1) {
0891         if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
0892             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0893                           ngx_set_file_time_n " \"%s\" failed", to);
0894             goto failed;
0895         }
0896     }
0897 
0898     rc = NGX_OK;
0899 
0900 failed:
0901 
0902     if (nfd != NGX_INVALID_FILE) {
0903         if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
0904             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0905                           ngx_close_file_n " \"%s\" failed", to);
0906         }
0907     }
0908 
0909     if (fd != NGX_INVALID_FILE) {
0910         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
0911             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0912                           ngx_close_file_n " \"%s\" failed", from);
0913         }
0914     }
0915 
0916     if (buf) {
0917         ngx_free(buf);
0918     }
0919 
0920     return rc;
0921 }
0922 
0923 
0924 /*
0925  * ctx->init_handler() - see ctx->alloc
0926  * ctx->file_handler() - file handler
0927  * ctx->pre_tree_handler() - handler is called before entering directory
0928  * ctx->post_tree_handler() - handler is called after leaving directory
0929  * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
0930  *
0931  * ctx->data - some data structure, it may be the same on all levels, or
0932  *     reallocated if ctx->alloc is nonzero
0933  *
0934  * ctx->alloc - a size of data structure that is allocated at every level
0935  *     and is initialized by ctx->init_handler()
0936  *
0937  * ctx->log - a log
0938  *
0939  * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
0940  */
0941 
0942 ngx_int_t
0943 ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
0944 {
0945     void       *data, *prev;
0946     u_char     *p, *name;
0947     size_t      len;
0948     ngx_int_t   rc;
0949     ngx_err_t   err;
0950     ngx_str_t   file, buf;
0951     ngx_dir_t   dir;
0952 
0953     ngx_str_null(&buf);
0954 
0955     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
0956                    "walk tree \"%V\"", tree);
0957 
0958     if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
0959         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
0960                       ngx_open_dir_n " \"%s\" failed", tree->data);
0961         return NGX_ERROR;
0962     }
0963 
0964     prev = ctx->data;
0965 
0966     if (ctx->alloc) {
0967         data = ngx_alloc(ctx->alloc, ctx->log);
0968         if (data == NULL) {
0969             goto failed;
0970         }
0971 
0972         if (ctx->init_handler(data, prev) == NGX_ABORT) {
0973             goto failed;
0974         }
0975 
0976         ctx->data = data;
0977 
0978     } else {
0979         data = NULL;
0980     }
0981 
0982     for ( ;; ) {
0983 
0984         ngx_set_errno(0);
0985 
0986         if (ngx_read_dir(&dir) == NGX_ERROR) {
0987             err = ngx_errno;
0988 
0989             if (err == NGX_ENOMOREFILES) {
0990                 rc = NGX_OK;
0991 
0992             } else {
0993                 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
0994                               ngx_read_dir_n " \"%s\" failed", tree->data);
0995                 rc = NGX_ERROR;
0996             }
0997 
0998             goto done;
0999         }
1000 
1001         len = ngx_de_namelen(&dir);
1002         name = ngx_de_name(&dir);
1003 
1004         ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1005                       "tree name %uz:\"%s\"", len, name);
1006 
1007         if (len == 1 && name[0] == '.') {
1008             continue;
1009         }
1010 
1011         if (len == 2 && name[0] == '.' && name[1] == '.') {
1012             continue;
1013         }
1014 
1015         file.len = tree->len + 1 + len;
1016 
1017         if (file.len + NGX_DIR_MASK_LEN > buf.len) {
1018 
1019             if (buf.len) {
1020                 ngx_free(buf.data);
1021             }
1022 
1023             buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
1024 
1025             buf.data = ngx_alloc(buf.len + 1, ctx->log);
1026             if (buf.data == NULL) {
1027                 goto failed;
1028             }
1029         }
1030 
1031         p = ngx_cpymem(buf.data, tree->data, tree->len);
1032         *p++ = '/';
1033         ngx_memcpy(p, name, len + 1);
1034 
1035         file.data = buf.data;
1036 
1037         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1038                        "tree path \"%s\"", file.data);
1039 
1040         if (!dir.valid_info) {
1041             if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
1042                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1043                               ngx_de_info_n " \"%s\" failed", file.data);
1044                 continue;
1045             }
1046         }
1047 
1048         if (ngx_de_is_file(&dir)) {
1049 
1050             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1051                            "tree file \"%s\"", file.data);
1052 
1053             ctx->size = ngx_de_size(&dir);
1054             ctx->fs_size = ngx_de_fs_size(&dir);
1055             ctx->access = ngx_de_access(&dir);
1056             ctx->mtime = ngx_de_mtime(&dir);
1057 
1058             if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
1059                 goto failed;
1060             }
1061 
1062         } else if (ngx_de_is_dir(&dir)) {
1063 
1064             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1065                            "tree enter dir \"%s\"", file.data);
1066 
1067             ctx->access = ngx_de_access(&dir);
1068             ctx->mtime = ngx_de_mtime(&dir);
1069 
1070             rc = ctx->pre_tree_handler(ctx, &file);
1071 
1072             if (rc == NGX_ABORT) {
1073                 goto failed;
1074             }
1075 
1076             if (rc == NGX_DECLINED) {
1077                 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1078                                "tree skip dir \"%s\"", file.data);
1079                 continue;
1080             }
1081 
1082             if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
1083                 goto failed;
1084             }
1085 
1086             ctx->access = ngx_de_access(&dir);
1087             ctx->mtime = ngx_de_mtime(&dir);
1088 
1089             if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
1090                 goto failed;
1091             }
1092 
1093         } else {
1094 
1095             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1096                            "tree special \"%s\"", file.data);
1097 
1098             if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
1099                 goto failed;
1100             }
1101         }
1102     }
1103 
1104 failed:
1105 
1106     rc = NGX_ABORT;
1107 
1108 done:
1109 
1110     if (buf.len) {
1111         ngx_free(buf.data);
1112     }
1113 
1114     if (data) {
1115         ngx_free(data);
1116         ctx->data = prev;
1117     }
1118 
1119     if (ngx_close_dir(&dir) == NGX_ERROR) {
1120         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1121                       ngx_close_dir_n " \"%s\" failed", tree->data);
1122     }
1123 
1124     return rc;
1125 }