Annotation of embedaddon/nginx/src/core/ngx_file.c, revision 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>