Annotation of embedaddon/nginx/src/core/ngx_file.c, revision 1.1.1.1

1.1       misho       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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>