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((const char *) path[i]->name.data, &fi)
0626             == NGX_FILE_ERROR)
0627         {
0628             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0629                           ngx_file_info_n " \"%s\" failed", path[i]->name.data);
0630             return NGX_ERROR;
0631         }
0632 
0633         if (fi.st_uid != user) {
0634             if (chown((const char *) path[i]->name.data, user, -1) == -1) {
0635                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0636                               "chown(\"%s\", %d) failed",
0637                               path[i]->name.data, user);
0638                 return NGX_ERROR;
0639             }
0640         }
0641 
0642         if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
0643                                                   != (S_IRUSR|S_IWUSR|S_IXUSR))
0644         {
0645             fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);
0646 
0647             if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
0648                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
0649                               "chmod() \"%s\" failed", path[i]->name.data);
0650                 return NGX_ERROR;
0651             }
0652         }
0653         }
0654 #endif
0655     }
0656 
0657     return NGX_OK;
0658 }
0659 
0660 
0661 ngx_int_t
0662 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
0663 {
0664     u_char           *name;
0665     ngx_err_t         err;
0666     ngx_copy_file_t   cf;
0667 
0668 #if !(NGX_WIN32)
0669 
0670     if (ext->access) {
0671         if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
0672             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0673                           ngx_change_file_access_n " \"%s\" failed", src->data);
0674             err = 0;
0675             goto failed;
0676         }
0677     }
0678 
0679 #endif
0680 
0681     if (ext->time != -1) {
0682         if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) {
0683             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0684                           ngx_set_file_time_n " \"%s\" failed", src->data);
0685             err = 0;
0686             goto failed;
0687         }
0688     }
0689 
0690     if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
0691         return NGX_OK;
0692     }
0693 
0694     err = ngx_errno;
0695 
0696     if (err == NGX_ENOPATH) {
0697 
0698         if (!ext->create_path) {
0699             goto failed;
0700         }
0701 
0702         err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access));
0703 
0704         if (err) {
0705             ngx_log_error(NGX_LOG_CRIT, ext->log, err,
0706                           ngx_create_dir_n " \"%s\" failed", to->data);
0707             err = 0;
0708             goto failed;
0709         }
0710 
0711         if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
0712             return NGX_OK;
0713         }
0714 
0715         err = ngx_errno;
0716     }
0717 
0718 #if (NGX_WIN32)
0719 
0720     if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) {
0721         err = ngx_win32_rename_file(src, to, ext->log);
0722 
0723         if (err == 0) {
0724             return NGX_OK;
0725         }
0726     }
0727 
0728 #endif
0729 
0730     if (err == NGX_EXDEV) {
0731 
0732         cf.size = -1;
0733         cf.buf_size = 0;
0734         cf.access = ext->access;
0735         cf.time = ext->time;
0736         cf.log = ext->log;
0737 
0738         name = ngx_alloc(to->len + 1 + 10 + 1, ext->log);
0739         if (name == NULL) {
0740             return NGX_ERROR;
0741         }
0742 
0743         (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data,
0744                            (uint32_t) ngx_next_temp_number(0));
0745 
0746         if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {
0747 
0748             if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) {
0749                 ngx_free(name);
0750 
0751                 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
0752                     ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0753                                   ngx_delete_file_n " \"%s\" failed",
0754                                   src->data);
0755                     return NGX_ERROR;
0756                 }
0757 
0758                 return NGX_OK;
0759             }
0760 
0761             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0762                           ngx_rename_file_n " \"%s\" to \"%s\" failed",
0763                           name, to->data);
0764 
0765             if (ngx_delete_file(name) == NGX_FILE_ERROR) {
0766                 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0767                               ngx_delete_file_n " \"%s\" failed", name);
0768 
0769             }
0770         }
0771 
0772         ngx_free(name);
0773 
0774         err = 0;
0775     }
0776 
0777 failed:
0778 
0779     if (ext->delete_file) {
0780         if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
0781             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
0782                           ngx_delete_file_n " \"%s\" failed", src->data);
0783         }
0784     }
0785 
0786     if (err) {
0787         ngx_log_error(NGX_LOG_CRIT, ext->log, err,
0788                       ngx_rename_file_n " \"%s\" to \"%s\" failed",
0789                       src->data, to->data);
0790     }
0791 
0792     return NGX_ERROR;
0793 }
0794 
0795 
0796 ngx_int_t
0797 ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
0798 {
0799     char             *buf;
0800     off_t             size;
0801     size_t            len;
0802     ssize_t           n;
0803     ngx_fd_t          fd, nfd;
0804     ngx_int_t         rc;
0805     ngx_file_info_t   fi;
0806 
0807     rc = NGX_ERROR;
0808     buf = NULL;
0809     nfd = NGX_INVALID_FILE;
0810 
0811     fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
0812 
0813     if (fd == NGX_INVALID_FILE) {
0814         ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
0815                       ngx_open_file_n " \"%s\" failed", from);
0816         goto failed;
0817     }
0818 
0819     if (cf->size != -1) {
0820         size = cf->size;
0821 
0822     } else {
0823         if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
0824             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0825                           ngx_fd_info_n " \"%s\" failed", from);
0826 
0827             goto failed;
0828         }
0829 
0830         size = ngx_file_size(&fi);
0831     }
0832 
0833     len = cf->buf_size ? cf->buf_size : 65536;
0834 
0835     if ((off_t) len > size) {
0836         len = (size_t) size;
0837     }
0838 
0839     buf = ngx_alloc(len, cf->log);
0840     if (buf == NULL) {
0841         goto failed;
0842     }
0843 
0844     nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
0845                         cf->access);
0846 
0847     if (nfd == NGX_INVALID_FILE) {
0848         ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
0849                       ngx_open_file_n " \"%s\" failed", to);
0850         goto failed;
0851     }
0852 
0853     while (size > 0) {
0854 
0855         if ((off_t) len > size) {
0856             len = (size_t) size;
0857         }
0858 
0859         n = ngx_read_fd(fd, buf, len);
0860 
0861         if (n == -1) {
0862             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0863                           ngx_read_fd_n " \"%s\" failed", from);
0864             goto failed;
0865         }
0866 
0867         if ((size_t) n != len) {
0868             ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
0869                           ngx_read_fd_n " has read only %z of %O from %s",
0870                           n, size, from);
0871             goto failed;
0872         }
0873 
0874         n = ngx_write_fd(nfd, buf, len);
0875 
0876         if (n == -1) {
0877             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0878                           ngx_write_fd_n " \"%s\" failed", to);
0879             goto failed;
0880         }
0881 
0882         if ((size_t) n != len) {
0883             ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
0884                           ngx_write_fd_n " has written only %z of %O to %s",
0885                           n, size, to);
0886             goto failed;
0887         }
0888 
0889         size -= n;
0890     }
0891 
0892     if (cf->time != -1) {
0893         if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
0894             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0895                           ngx_set_file_time_n " \"%s\" failed", to);
0896             goto failed;
0897         }
0898     }
0899 
0900     rc = NGX_OK;
0901 
0902 failed:
0903 
0904     if (nfd != NGX_INVALID_FILE) {
0905         if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
0906             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0907                           ngx_close_file_n " \"%s\" failed", to);
0908         }
0909     }
0910 
0911     if (fd != NGX_INVALID_FILE) {
0912         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
0913             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
0914                           ngx_close_file_n " \"%s\" failed", from);
0915         }
0916     }
0917 
0918     if (buf) {
0919         ngx_free(buf);
0920     }
0921 
0922     return rc;
0923 }
0924 
0925 
0926 /*
0927  * ctx->init_handler() - see ctx->alloc
0928  * ctx->file_handler() - file handler
0929  * ctx->pre_tree_handler() - handler is called before entering directory
0930  * ctx->post_tree_handler() - handler is called after leaving directory
0931  * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
0932  *
0933  * ctx->data - some data structure, it may be the same on all levels, or
0934  *     reallocated if ctx->alloc is nonzero
0935  *
0936  * ctx->alloc - a size of data structure that is allocated at every level
0937  *     and is initialized by ctx->init_handler()
0938  *
0939  * ctx->log - a log
0940  *
0941  * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
0942  */
0943 
0944 ngx_int_t
0945 ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
0946 {
0947     void       *data, *prev;
0948     u_char     *p, *name;
0949     size_t      len;
0950     ngx_int_t   rc;
0951     ngx_err_t   err;
0952     ngx_str_t   file, buf;
0953     ngx_dir_t   dir;
0954 
0955     ngx_str_null(&buf);
0956 
0957     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
0958                    "walk tree \"%V\"", tree);
0959 
0960     if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
0961         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
0962                       ngx_open_dir_n " \"%s\" failed", tree->data);
0963         return NGX_ERROR;
0964     }
0965 
0966     prev = ctx->data;
0967 
0968     if (ctx->alloc) {
0969         data = ngx_alloc(ctx->alloc, ctx->log);
0970         if (data == NULL) {
0971             goto failed;
0972         }
0973 
0974         if (ctx->init_handler(data, prev) == NGX_ABORT) {
0975             goto failed;
0976         }
0977 
0978         ctx->data = data;
0979 
0980     } else {
0981         data = NULL;
0982     }
0983 
0984     for ( ;; ) {
0985 
0986         ngx_set_errno(0);
0987 
0988         if (ngx_read_dir(&dir) == NGX_ERROR) {
0989             err = ngx_errno;
0990 
0991             if (err == NGX_ENOMOREFILES) {
0992                 rc = NGX_OK;
0993 
0994             } else {
0995                 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
0996                               ngx_read_dir_n " \"%s\" failed", tree->data);
0997                 rc = NGX_ERROR;
0998             }
0999 
1000             goto done;
1001         }
1002 
1003         len = ngx_de_namelen(&dir);
1004         name = ngx_de_name(&dir);
1005 
1006         ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1007                       "tree name %uz:\"%s\"", len, name);
1008 
1009         if (len == 1 && name[0] == '.') {
1010             continue;
1011         }
1012 
1013         if (len == 2 && name[0] == '.' && name[1] == '.') {
1014             continue;
1015         }
1016 
1017         file.len = tree->len + 1 + len;
1018 
1019         if (file.len + NGX_DIR_MASK_LEN > buf.len) {
1020 
1021             if (buf.len) {
1022                 ngx_free(buf.data);
1023             }
1024 
1025             buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
1026 
1027             buf.data = ngx_alloc(buf.len + 1, ctx->log);
1028             if (buf.data == NULL) {
1029                 goto failed;
1030             }
1031         }
1032 
1033         p = ngx_cpymem(buf.data, tree->data, tree->len);
1034         *p++ = '/';
1035         ngx_memcpy(p, name, len + 1);
1036 
1037         file.data = buf.data;
1038 
1039         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1040                        "tree path \"%s\"", file.data);
1041 
1042         if (!dir.valid_info) {
1043             if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
1044                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1045                               ngx_de_info_n " \"%s\" failed", file.data);
1046                 continue;
1047             }
1048         }
1049 
1050         if (ngx_de_is_file(&dir)) {
1051 
1052             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1053                            "tree file \"%s\"", file.data);
1054 
1055             ctx->size = ngx_de_size(&dir);
1056             ctx->fs_size = ngx_de_fs_size(&dir);
1057             ctx->access = ngx_de_access(&dir);
1058             ctx->mtime = ngx_de_mtime(&dir);
1059 
1060             if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
1061                 goto failed;
1062             }
1063 
1064         } else if (ngx_de_is_dir(&dir)) {
1065 
1066             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1067                            "tree enter dir \"%s\"", file.data);
1068 
1069             ctx->access = ngx_de_access(&dir);
1070             ctx->mtime = ngx_de_mtime(&dir);
1071 
1072             rc = ctx->pre_tree_handler(ctx, &file);
1073 
1074             if (rc == NGX_ABORT) {
1075                 goto failed;
1076             }
1077 
1078             if (rc == NGX_DECLINED) {
1079                 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1080                                "tree skip dir \"%s\"", file.data);
1081                 continue;
1082             }
1083 
1084             if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
1085                 goto failed;
1086             }
1087 
1088             ctx->access = ngx_de_access(&dir);
1089             ctx->mtime = ngx_de_mtime(&dir);
1090 
1091             if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
1092                 goto failed;
1093             }
1094 
1095         } else {
1096 
1097             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
1098                            "tree special \"%s\"", file.data);
1099 
1100             if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
1101                 goto failed;
1102             }
1103         }
1104     }
1105 
1106 failed:
1107 
1108     rc = NGX_ABORT;
1109 
1110 done:
1111 
1112     if (buf.len) {
1113         ngx_free(buf.data);
1114     }
1115 
1116     if (data) {
1117         ngx_free(data);
1118         ctx->data = prev;
1119     }
1120 
1121     if (ngx_close_dir(&dir) == NGX_ERROR) {
1122         ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
1123                       ngx_close_dir_n " \"%s\" failed", tree->data);
1124     }
1125 
1126     return rc;
1127 }