src/os/win32/ngx_files.c - nginx source code

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. #define NGX_UTF16_BUFLEN  256
  8. #define NGX_UTF8_BUFLEN   512

  9. static ngx_int_t ngx_win32_check_filename(u_short *u, size_t len,
  10.     ngx_uint_t dirname);
  11. static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len,
  12.     size_t reserved);
  13. static u_char *ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len,
  14.     size_t *allocated);
  15. uint32_t ngx_utf16_decode(u_short **u, size_t n);


  16. /* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */

  17. ngx_fd_t
  18. ngx_open_file(u_char *name, u_long mode, u_long create, u_long access)
  19. {
  20.     size_t      len;
  21.     u_short    *u;
  22.     ngx_fd_t    fd;
  23.     ngx_err_t   err;
  24.     u_short     utf16[NGX_UTF16_BUFLEN];

  25.     len = NGX_UTF16_BUFLEN;
  26.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  27.     if (u == NULL) {
  28.         return INVALID_HANDLE_VALUE;
  29.     }

  30.     fd = INVALID_HANDLE_VALUE;

  31.     if (create == NGX_FILE_OPEN
  32.         && ngx_win32_check_filename(u, len, 0) != NGX_OK)
  33.     {
  34.         goto failed;
  35.     }

  36.     fd = CreateFileW(u, mode,
  37.                      FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  38.                      NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL);

  39. failed:

  40.     if (u != utf16) {
  41.         err = ngx_errno;
  42.         ngx_free(u);
  43.         ngx_set_errno(err);
  44.     }

  45.     return fd;
  46. }


  47. ngx_fd_t
  48. ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
  49. {
  50.     size_t      len;
  51.     u_short    *u;
  52.     ngx_fd_t    fd;
  53.     ngx_err_t   err;
  54.     u_short     utf16[NGX_UTF16_BUFLEN];

  55.     len = NGX_UTF16_BUFLEN;
  56.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  57.     if (u == NULL) {
  58.         return INVALID_HANDLE_VALUE;
  59.     }

  60.     fd = CreateFileW(u,
  61.                      GENERIC_READ|GENERIC_WRITE,
  62.                      FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  63.                      NULL,
  64.                      CREATE_NEW,
  65.                      persistent ? 0:
  66.                          FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,
  67.                      NULL);

  68.     if (u != utf16) {
  69.         err = ngx_errno;
  70.         ngx_free(u);
  71.         ngx_set_errno(err);
  72.     }

  73.     return fd;
  74. }


  75. ssize_t
  76. ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
  77. {
  78.     u_long      n;
  79.     ngx_err_t   err;
  80.     OVERLAPPED  ovlp, *povlp;

  81.     ovlp.Internal = 0;
  82.     ovlp.InternalHigh = 0;
  83.     ovlp.Offset = (u_long) offset;
  84.     ovlp.OffsetHigh = (u_long) (offset >> 32);
  85.     ovlp.hEvent = NULL;

  86.     povlp = &ovlp;

  87.     if (ReadFile(file->fd, buf, size, &n, povlp) == 0) {
  88.         err = ngx_errno;

  89.         if (err == ERROR_HANDLE_EOF) {
  90.             return 0;
  91.         }

  92.         ngx_log_error(NGX_LOG_ERR, file->log, err,
  93.                       "ReadFile() \"%s\" failed", file->name.data);
  94.         return NGX_ERROR;
  95.     }

  96.     file->offset += n;

  97.     return n;
  98. }


  99. ssize_t
  100. ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
  101. {
  102.     u_long      n;
  103.     OVERLAPPED  ovlp, *povlp;

  104.     ovlp.Internal = 0;
  105.     ovlp.InternalHigh = 0;
  106.     ovlp.Offset = (u_long) offset;
  107.     ovlp.OffsetHigh = (u_long) (offset >> 32);
  108.     ovlp.hEvent = NULL;

  109.     povlp = &ovlp;

  110.     if (WriteFile(file->fd, buf, size, &n, povlp) == 0) {
  111.         ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno,
  112.                       "WriteFile() \"%s\" failed", file->name.data);
  113.         return NGX_ERROR;
  114.     }

  115.     if (n != size) {
  116.         ngx_log_error(NGX_LOG_CRIT, file->log, 0,
  117.                       "WriteFile() \"%s\" has written only %ul of %uz",
  118.                       file->name.data, n, size);
  119.         return NGX_ERROR;
  120.     }

  121.     file->offset += n;

  122.     return n;
  123. }


  124. ssize_t
  125. ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
  126.     ngx_pool_t *pool)
  127. {
  128.     u_char   *buf, *prev;
  129.     size_t    size;
  130.     ssize_t   total, n;

  131.     total = 0;

  132.     while (cl) {
  133.         buf = cl->buf->pos;
  134.         prev = buf;
  135.         size = 0;

  136.         /* coalesce the neighbouring bufs */

  137.         while (cl && prev == cl->buf->pos) {
  138.             size += cl->buf->last - cl->buf->pos;
  139.             prev = cl->buf->last;
  140.             cl = cl->next;
  141.         }

  142.         n = ngx_write_file(file, buf, size, offset);

  143.         if (n == NGX_ERROR) {
  144.             return NGX_ERROR;
  145.         }

  146.         total += n;
  147.         offset += n;
  148.     }

  149.     return total;
  150. }


  151. ssize_t
  152. ngx_read_fd(ngx_fd_t fd, void *buf, size_t size)
  153. {
  154.     u_long  n;

  155.     if (ReadFile(fd, buf, size, &n, NULL) != 0) {
  156.         return (size_t) n;
  157.     }

  158.     return -1;
  159. }


  160. ssize_t
  161. ngx_write_fd(ngx_fd_t fd, void *buf, size_t size)
  162. {
  163.     u_long  n;

  164.     if (WriteFile(fd, buf, size, &n, NULL) != 0) {
  165.         return (size_t) n;
  166.     }

  167.     return -1;
  168. }


  169. ssize_t
  170. ngx_write_console(ngx_fd_t fd, void *buf, size_t size)
  171. {
  172.     u_long  n;

  173.     (void) CharToOemBuff(buf, buf, size);

  174.     if (WriteFile(fd, buf, size, &n, NULL) != 0) {
  175.         return (size_t) n;
  176.     }

  177.     return -1;
  178. }


  179. ngx_int_t
  180. ngx_delete_file(u_char *name)
  181. {
  182.     long        rc;
  183.     size_t      len;
  184.     u_short    *u;
  185.     ngx_err_t   err;
  186.     u_short     utf16[NGX_UTF16_BUFLEN];

  187.     len = NGX_UTF16_BUFLEN;
  188.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  189.     if (u == NULL) {
  190.         return NGX_FILE_ERROR;
  191.     }

  192.     rc = NGX_FILE_ERROR;

  193.     if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
  194.         goto failed;
  195.     }

  196.     rc = DeleteFileW(u);

  197. failed:

  198.     if (u != utf16) {
  199.         err = ngx_errno;
  200.         ngx_free(u);
  201.         ngx_set_errno(err);
  202.     }

  203.     return rc;
  204. }


  205. ngx_int_t
  206. ngx_rename_file(u_char *from, u_char *to)
  207. {
  208.     long        rc;
  209.     size_t      len;
  210.     u_short    *fu, *tu;
  211.     ngx_err_t   err;
  212.     u_short     utf16f[NGX_UTF16_BUFLEN];
  213.     u_short     utf16t[NGX_UTF16_BUFLEN];

  214.     len = NGX_UTF16_BUFLEN;
  215.     fu = ngx_utf8_to_utf16(utf16f, from, &len, 0);

  216.     if (fu == NULL) {
  217.         return NGX_FILE_ERROR;
  218.     }

  219.     rc = NGX_FILE_ERROR;
  220.     tu = NULL;

  221.     if (ngx_win32_check_filename(fu, len, 0) != NGX_OK) {
  222.         goto failed;
  223.     }

  224.     len = NGX_UTF16_BUFLEN;
  225.     tu = ngx_utf8_to_utf16(utf16t, to, &len, 0);

  226.     if (tu == NULL) {
  227.         goto failed;
  228.     }

  229.     if (ngx_win32_check_filename(tu, len, 1) != NGX_OK) {
  230.         goto failed;
  231.     }

  232.     rc = MoveFileW(fu, tu);

  233. failed:

  234.     if (fu != utf16f) {
  235.         err = ngx_errno;
  236.         ngx_free(fu);
  237.         ngx_set_errno(err);
  238.     }

  239.     if (tu && tu != utf16t) {
  240.         err = ngx_errno;
  241.         ngx_free(tu);
  242.         ngx_set_errno(err);
  243.     }

  244.     return rc;
  245. }


  246. ngx_err_t
  247. ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log)
  248. {
  249.     u_char             *name;
  250.     ngx_err_t           err;
  251.     ngx_uint_t          collision;
  252.     ngx_atomic_uint_t   num;

  253.     name = ngx_alloc(to->len + 1 + NGX_ATOMIC_T_LEN + 1 + sizeof("DELETE"),
  254.                      log);
  255.     if (name == NULL) {
  256.         return NGX_ENOMEM;
  257.     }

  258.     ngx_memcpy(name, to->data, to->len);

  259.     collision = 0;

  260.     /* mutex_lock() (per cache or single ?) */

  261.     for ( ;; ) {
  262.         num = ngx_next_temp_number(collision);

  263.         ngx_sprintf(name + to->len, ".%0muA.DELETE%Z", num);

  264.         if (ngx_rename_file(to->data, name) != NGX_FILE_ERROR) {
  265.             break;
  266.         }

  267.         err = ngx_errno;

  268.         if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) {
  269.             collision = 1;
  270.             continue;
  271.         }

  272.         ngx_log_error(NGX_LOG_CRIT, log, err,
  273.                       "MoveFile() \"%s\" to \"%s\" failed", to->data, name);
  274.         goto failed;
  275.     }

  276.     if (ngx_rename_file(from->data, to->data) == NGX_FILE_ERROR) {
  277.         err = ngx_errno;

  278.     } else {
  279.         err = 0;
  280.     }

  281.     if (ngx_delete_file(name) == NGX_FILE_ERROR) {
  282.         ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
  283.                       "DeleteFile() \"%s\" failed", name);
  284.     }

  285. failed:

  286.     /* mutex_unlock() */

  287.     ngx_free(name);

  288.     return err;
  289. }


  290. ngx_int_t
  291. ngx_file_info(u_char *file, ngx_file_info_t *sb)
  292. {
  293.     size_t                      len;
  294.     long                        rc;
  295.     u_short                    *u;
  296.     ngx_err_t                   err;
  297.     WIN32_FILE_ATTRIBUTE_DATA   fa;
  298.     u_short                     utf16[NGX_UTF16_BUFLEN];

  299.     len = NGX_UTF16_BUFLEN;

  300.     u = ngx_utf8_to_utf16(utf16, file, &len, 0);

  301.     if (u == NULL) {
  302.         return NGX_FILE_ERROR;
  303.     }

  304.     rc = NGX_FILE_ERROR;

  305.     if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
  306.         goto failed;
  307.     }

  308.     rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa);

  309.     sb->dwFileAttributes = fa.dwFileAttributes;
  310.     sb->ftCreationTime = fa.ftCreationTime;
  311.     sb->ftLastAccessTime = fa.ftLastAccessTime;
  312.     sb->ftLastWriteTime = fa.ftLastWriteTime;
  313.     sb->nFileSizeHigh = fa.nFileSizeHigh;
  314.     sb->nFileSizeLow = fa.nFileSizeLow;

  315. failed:

  316.     if (u != utf16) {
  317.         err = ngx_errno;
  318.         ngx_free(u);
  319.         ngx_set_errno(err);
  320.     }

  321.     return rc;
  322. }


  323. ngx_int_t
  324. ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s)
  325. {
  326.     uint64_t  intervals;
  327.     FILETIME  ft;

  328.     /* 116444736000000000 is commented in src/os/win32/ngx_time.c */

  329.     intervals = s * 10000000 + 116444736000000000;

  330.     ft.dwLowDateTime = (DWORD) intervals;
  331.     ft.dwHighDateTime = (DWORD) (intervals >> 32);

  332.     if (SetFileTime(fd, NULL, NULL, &ft) != 0) {
  333.         return NGX_OK;
  334.     }

  335.     return NGX_ERROR;
  336. }


  337. ngx_int_t
  338. ngx_create_file_mapping(ngx_file_mapping_t *fm)
  339. {
  340.     LARGE_INTEGER  size;

  341.     fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
  342.                            NGX_FILE_DEFAULT_ACCESS);

  343.     if (fm->fd == NGX_INVALID_FILE) {
  344.         ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
  345.                       ngx_open_file_n " \"%s\" failed", fm->name);
  346.         return NGX_ERROR;
  347.     }

  348.     fm->handle = NULL;

  349.     size.QuadPart = fm->size;

  350.     if (SetFilePointerEx(fm->fd, size, NULL, FILE_BEGIN) == 0) {
  351.         ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
  352.                       "SetFilePointerEx(\"%s\", %uz) failed",
  353.                       fm->name, fm->size);
  354.         goto failed;
  355.     }

  356.     if (SetEndOfFile(fm->fd) == 0) {
  357.         ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
  358.                       "SetEndOfFile() \"%s\" failed", fm->name);
  359.         goto failed;
  360.     }

  361.     fm->handle = CreateFileMapping(fm->fd, NULL, PAGE_READWRITE,
  362.                                    (u_long) ((off_t) fm->size >> 32),
  363.                                    (u_long) ((off_t) fm->size & 0xffffffff),
  364.                                    NULL);
  365.     if (fm->handle == NULL) {
  366.         ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
  367.                       "CreateFileMapping(%s, %uz) failed",
  368.                       fm->name, fm->size);
  369.         goto failed;
  370.     }

  371.     fm->addr = MapViewOfFile(fm->handle, FILE_MAP_WRITE, 0, 0, 0);

  372.     if (fm->addr != NULL) {
  373.         return NGX_OK;
  374.     }

  375.     ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
  376.                   "MapViewOfFile(%uz) of file mapping \"%s\" failed",
  377.                   fm->size, fm->name);

  378. failed:

  379.     if (fm->handle) {
  380.         if (CloseHandle(fm->handle) == 0) {
  381.             ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
  382.                           "CloseHandle() of file mapping \"%s\" failed",
  383.                           fm->name);
  384.         }
  385.     }

  386.     if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
  387.         ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
  388.                       ngx_close_file_n " \"%s\" failed", fm->name);
  389.     }

  390.     return NGX_ERROR;
  391. }


  392. void
  393. ngx_close_file_mapping(ngx_file_mapping_t *fm)
  394. {
  395.     if (UnmapViewOfFile(fm->addr) == 0) {
  396.         ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
  397.                       "UnmapViewOfFile(%p) of file mapping \"%s\" failed",
  398.                       fm->addr, &fm->name);
  399.     }

  400.     if (CloseHandle(fm->handle) == 0) {
  401.         ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
  402.                       "CloseHandle() of file mapping \"%s\" failed",
  403.                       &fm->name);
  404.     }

  405.     if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
  406.         ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
  407.                       ngx_close_file_n " \"%s\" failed", fm->name);
  408.     }
  409. }


  410. u_char *
  411. ngx_realpath(u_char *path, u_char *resolved)
  412. {
  413.     /* STUB */
  414.     return path;
  415. }


  416. size_t
  417. ngx_getcwd(u_char *buf, size_t size)
  418. {
  419.     u_char   *p;
  420.     size_t    n;
  421.     u_short   utf16[NGX_MAX_PATH];

  422.     n = GetCurrentDirectoryW(NGX_MAX_PATH, utf16);

  423.     if (n == 0) {
  424.         return 0;
  425.     }

  426.     if (n > NGX_MAX_PATH) {
  427.         ngx_set_errno(ERROR_INSUFFICIENT_BUFFER);
  428.         return 0;
  429.     }

  430.     p = ngx_utf16_to_utf8(buf, utf16, &size, NULL);

  431.     if (p == NULL) {
  432.         return 0;
  433.     }

  434.     if (p != buf) {
  435.         ngx_free(p);
  436.         ngx_set_errno(ERROR_INSUFFICIENT_BUFFER);
  437.         return 0;
  438.     }

  439.     return size - 1;
  440. }


  441. ngx_int_t
  442. ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir)
  443. {
  444.     size_t      len;
  445.     u_short    *u, *p;
  446.     ngx_err_t   err;
  447.     u_short     utf16[NGX_UTF16_BUFLEN];

  448.     len = NGX_UTF16_BUFLEN - 2;
  449.     u = ngx_utf8_to_utf16(utf16, name->data, &len, 2);

  450.     if (u == NULL) {
  451.         return NGX_ERROR;
  452.     }

  453.     if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
  454.         goto failed;
  455.     }

  456.     p = &u[len - 1];

  457.     *p++ = '/';
  458.     *p++ = '*';
  459.     *p = '\0';

  460.     dir->dir = FindFirstFileW(u, &dir->finddata);

  461.     if (dir->dir == INVALID_HANDLE_VALUE) {
  462.         goto failed;
  463.     }

  464.     if (u != utf16) {
  465.         ngx_free(u);
  466.     }

  467.     dir->valid_info = 1;
  468.     dir->ready = 1;
  469.     dir->name = NULL;
  470.     dir->allocated = 0;

  471.     return NGX_OK;

  472. failed:

  473.     if (u != utf16) {
  474.         err = ngx_errno;
  475.         ngx_free(u);
  476.         ngx_set_errno(err);
  477.     }

  478.     return NGX_ERROR;
  479. }


  480. ngx_int_t
  481. ngx_read_dir(ngx_dir_t *dir)
  482. {
  483.     u_char  *name;
  484.     size_t   len, allocated;

  485.     if (dir->ready) {
  486.         dir->ready = 0;
  487.         goto convert;
  488.     }

  489.     if (FindNextFileW(dir->dir, &dir->finddata) != 0) {
  490.         dir->type = 1;
  491.         goto convert;
  492.     }

  493.     return NGX_ERROR;

  494. convert:

  495.     name = dir->name;
  496.     len = dir->allocated;

  497.     name = ngx_utf16_to_utf8(name, dir->finddata.cFileName, &len, &allocated);

  498.     if (name == NULL) {
  499.         return NGX_ERROR;
  500.     }

  501.     if (name != dir->name) {

  502.         if (dir->name) {
  503.             ngx_free(dir->name);
  504.         }

  505.         dir->name = name;
  506.         dir->allocated = allocated;
  507.     }

  508.     dir->namelen = len - 1;

  509.     return NGX_OK;
  510. }


  511. ngx_int_t
  512. ngx_close_dir(ngx_dir_t *dir)
  513. {
  514.     if (dir->name) {
  515.         ngx_free(dir->name);
  516.     }

  517.     if (FindClose(dir->dir) == 0) {
  518.         return NGX_ERROR;
  519.     }

  520.     return NGX_OK;
  521. }


  522. ngx_int_t
  523. ngx_create_dir(u_char *name, ngx_uint_t access)
  524. {
  525.     long        rc;
  526.     size_t      len;
  527.     u_short    *u;
  528.     ngx_err_t   err;
  529.     u_short     utf16[NGX_UTF16_BUFLEN];

  530.     len = NGX_UTF16_BUFLEN;
  531.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  532.     if (u == NULL) {
  533.         return NGX_FILE_ERROR;
  534.     }

  535.     rc = NGX_FILE_ERROR;

  536.     if (ngx_win32_check_filename(u, len, 1) != NGX_OK) {
  537.         goto failed;
  538.     }

  539.     rc = CreateDirectoryW(u, NULL);

  540. failed:

  541.     if (u != utf16) {
  542.         err = ngx_errno;
  543.         ngx_free(u);
  544.         ngx_set_errno(err);
  545.     }

  546.     return rc;
  547. }


  548. ngx_int_t
  549. ngx_delete_dir(u_char *name)
  550. {
  551.     long        rc;
  552.     size_t      len;
  553.     u_short    *u;
  554.     ngx_err_t   err;
  555.     u_short     utf16[NGX_UTF16_BUFLEN];

  556.     len = NGX_UTF16_BUFLEN;
  557.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  558.     if (u == NULL) {
  559.         return NGX_FILE_ERROR;
  560.     }

  561.     rc = NGX_FILE_ERROR;

  562.     if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
  563.         goto failed;
  564.     }

  565.     rc = RemoveDirectoryW(u);

  566. failed:

  567.     if (u != utf16) {
  568.         err = ngx_errno;
  569.         ngx_free(u);
  570.         ngx_set_errno(err);
  571.     }

  572.     return rc;
  573. }


  574. ngx_int_t
  575. ngx_open_glob(ngx_glob_t *gl)
  576. {
  577.     u_char     *p;
  578.     size_t      len;
  579.     u_short    *u;
  580.     ngx_err_t   err;
  581.     u_short     utf16[NGX_UTF16_BUFLEN];

  582.     len = NGX_UTF16_BUFLEN;
  583.     u = ngx_utf8_to_utf16(utf16, gl->pattern, &len, 0);

  584.     if (u == NULL) {
  585.         return NGX_ERROR;
  586.     }

  587.     gl->dir = FindFirstFileW(u, &gl->finddata);

  588.     if (gl->dir == INVALID_HANDLE_VALUE) {

  589.         err = ngx_errno;

  590.         if (u != utf16) {
  591.             ngx_free(u);
  592.         }

  593.         if ((err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
  594.              && gl->test)
  595.         {
  596.             gl->no_match = 1;
  597.             return NGX_OK;
  598.         }

  599.         ngx_set_errno(err);

  600.         return NGX_ERROR;
  601.     }

  602.     for (p = gl->pattern; *p; p++) {
  603.         if (*p == '/') {
  604.             gl->last = p + 1 - gl->pattern;
  605.         }
  606.     }

  607.     if (u != utf16) {
  608.         ngx_free(u);
  609.     }

  610.     gl->ready = 1;

  611.     return NGX_OK;
  612. }


  613. ngx_int_t
  614. ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name)
  615. {
  616.     u_char     *p;
  617.     size_t      len;
  618.     ngx_err_t   err;
  619.     u_char      utf8[NGX_UTF8_BUFLEN];

  620.     if (gl->no_match) {
  621.         return NGX_DONE;
  622.     }

  623.     if (gl->ready) {
  624.         gl->ready = 0;
  625.         goto convert;
  626.     }

  627.     ngx_free(gl->name.data);
  628.     gl->name.data = NULL;

  629.     if (FindNextFileW(gl->dir, &gl->finddata) != 0) {
  630.         goto convert;
  631.     }

  632.     err = ngx_errno;

  633.     if (err == NGX_ENOMOREFILES) {
  634.         return NGX_DONE;
  635.     }

  636.     ngx_log_error(NGX_LOG_ALERT, gl->log, err,
  637.                   "FindNextFile(%s) failed", gl->pattern);

  638.     return NGX_ERROR;

  639. convert:

  640.     len = NGX_UTF8_BUFLEN;
  641.     p = ngx_utf16_to_utf8(utf8, gl->finddata.cFileName, &len, NULL);

  642.     if (p == NULL) {
  643.         return NGX_ERROR;
  644.     }

  645.     gl->name.len = gl->last + len - 1;

  646.     gl->name.data = ngx_alloc(gl->name.len + 1, gl->log);
  647.     if (gl->name.data == NULL) {
  648.         goto failed;
  649.     }

  650.     ngx_memcpy(gl->name.data, gl->pattern, gl->last);
  651.     ngx_cpystrn(gl->name.data + gl->last, p, len);

  652.     if (p != utf8) {
  653.         ngx_free(p);
  654.     }

  655.     *name = gl->name;

  656.     return NGX_OK;

  657. failed:

  658.     if (p != utf8) {
  659.         err = ngx_errno;
  660.         ngx_free(p);
  661.         ngx_set_errno(err);
  662.     }

  663.     return NGX_ERROR;
  664. }


  665. void
  666. ngx_close_glob(ngx_glob_t *gl)
  667. {
  668.     if (gl->name.data) {
  669.         ngx_free(gl->name.data);
  670.     }

  671.     if (gl->dir == INVALID_HANDLE_VALUE) {
  672.         return;
  673.     }

  674.     if (FindClose(gl->dir) == 0) {
  675.         ngx_log_error(NGX_LOG_ALERT, gl->log, ngx_errno,
  676.                       "FindClose(%s) failed", gl->pattern);
  677.     }
  678. }


  679. ngx_int_t
  680. ngx_de_info(u_char *name, ngx_dir_t *dir)
  681. {
  682.     return NGX_OK;
  683. }


  684. ngx_int_t
  685. ngx_de_link_info(u_char *name, ngx_dir_t *dir)
  686. {
  687.     return NGX_OK;
  688. }


  689. ngx_int_t
  690. ngx_read_ahead(ngx_fd_t fd, size_t n)
  691. {
  692.     return ~NGX_FILE_ERROR;
  693. }


  694. ngx_int_t
  695. ngx_directio_on(ngx_fd_t fd)
  696. {
  697.     return ~NGX_FILE_ERROR;
  698. }


  699. ngx_int_t
  700. ngx_directio_off(ngx_fd_t fd)
  701. {
  702.     return ~NGX_FILE_ERROR;
  703. }


  704. size_t
  705. ngx_fs_bsize(u_char *name)
  706. {
  707.     u_long    sc, bs, nfree, ncl;
  708.     size_t    len;
  709.     u_short  *u;
  710.     u_short   utf16[NGX_UTF16_BUFLEN];

  711.     len = NGX_UTF16_BUFLEN;
  712.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  713.     if (u == NULL) {
  714.         return 512;
  715.     }

  716.     if (GetDiskFreeSpaceW(u, &sc, &bs, &nfree, &ncl) == 0) {

  717.         if (u != utf16) {
  718.             ngx_free(u);
  719.         }

  720.         return 512;
  721.     }

  722.     if (u != utf16) {
  723.         ngx_free(u);
  724.     }

  725.     return sc * bs;
  726. }


  727. off_t
  728. ngx_fs_available(u_char *name)
  729. {
  730.     size_t           len;
  731.     u_short         *u;
  732.     ULARGE_INTEGER   navail;
  733.     u_short          utf16[NGX_UTF16_BUFLEN];

  734.     len = NGX_UTF16_BUFLEN;
  735.     u = ngx_utf8_to_utf16(utf16, name, &len, 0);

  736.     if (u == NULL) {
  737.         return NGX_MAX_OFF_T_VALUE;
  738.     }

  739.     if (GetDiskFreeSpaceExW(u, &navail, NULL, NULL) == 0) {

  740.         if (u != utf16) {
  741.             ngx_free(u);
  742.         }

  743.         return NGX_MAX_OFF_T_VALUE;
  744.     }

  745.     if (u != utf16) {
  746.         ngx_free(u);
  747.     }

  748.     return (off_t) navail.QuadPart;
  749. }


  750. static ngx_int_t
  751. ngx_win32_check_filename(u_short *u, size_t len, ngx_uint_t dirname)
  752. {
  753.     u_long      n;
  754.     u_short    *lu, *p, *slash, ch;
  755.     ngx_err_t   err;
  756.     enum {
  757.         sw_start = 0,
  758.         sw_normal,
  759.         sw_after_slash,
  760.         sw_after_colon,
  761.         sw_after_dot
  762.     } state;

  763.     /* check for NTFS streams (":"), trailing dots and spaces */

  764.     lu = NULL;
  765.     slash = NULL;
  766.     state = sw_start;

  767. #if (NGX_SUPPRESS_WARN)
  768.     ch = 0;
  769. #endif

  770.     for (p = u; *p; p++) {
  771.         ch = *p;

  772.         switch (state) {

  773.         case sw_start:

  774.             /*
  775.              * skip till first "/" to allow paths starting with drive and
  776.              * relative path, like "c:html/"
  777.              */

  778.             if (ch == '/' || ch == '\\') {
  779.                 state = sw_after_slash;
  780.                 slash = p;
  781.             }

  782.             break;

  783.         case sw_normal:

  784.             if (ch == ':') {
  785.                 state = sw_after_colon;
  786.                 break;
  787.             }

  788.             if (ch == '.' || ch == ' ') {
  789.                 state = sw_after_dot;
  790.                 break;
  791.             }

  792.             if (ch == '/' || ch == '\\') {
  793.                 state = sw_after_slash;
  794.                 slash = p;
  795.                 break;
  796.             }

  797.             break;

  798.         case sw_after_slash:

  799.             if (ch == '/' || ch == '\\') {
  800.                 break;
  801.             }

  802.             if (ch == '.') {
  803.                 break;
  804.             }

  805.             if (ch == ':') {
  806.                 state = sw_after_colon;
  807.                 break;
  808.             }

  809.             state = sw_normal;
  810.             break;

  811.         case sw_after_colon:

  812.             if (ch == '/' || ch == '\\') {
  813.                 state = sw_after_slash;
  814.                 slash = p;
  815.                 break;
  816.             }

  817.             goto invalid;

  818.         case sw_after_dot:

  819.             if (ch == '/' || ch == '\\') {
  820.                 goto invalid;
  821.             }

  822.             if (ch == ':') {
  823.                 goto invalid;
  824.             }

  825.             if (ch == '.' || ch == ' ') {
  826.                 break;
  827.             }

  828.             state = sw_normal;
  829.             break;
  830.         }
  831.     }

  832.     if (state == sw_after_dot) {
  833.         goto invalid;
  834.     }

  835.     if (dirname && slash) {
  836.         ch = *slash;
  837.         *slash = '\0';
  838.         len = slash - u + 1;
  839.     }

  840.     /* check if long name match */

  841.     lu = malloc(len * 2);
  842.     if (lu == NULL) {
  843.         return NGX_ERROR;
  844.     }

  845.     n = GetLongPathNameW(u, lu, len);

  846.     if (n == 0) {

  847.         if (dirname && slash && ngx_errno == NGX_ENOENT) {
  848.             ngx_set_errno(NGX_ENOPATH);
  849.         }

  850.         goto failed;
  851.     }

  852.     if (n != len - 1 || _wcsicmp(u, lu) != 0) {
  853.         goto invalid;
  854.     }

  855.     if (dirname && slash) {
  856.         *slash = ch;
  857.     }

  858.     ngx_free(lu);

  859.     return NGX_OK;

  860. invalid:

  861.     ngx_set_errno(NGX_ENOENT);

  862. failed:

  863.     if (dirname && slash) {
  864.         *slash = ch;
  865.     }

  866.     if (lu) {
  867.         err = ngx_errno;
  868.         ngx_free(lu);
  869.         ngx_set_errno(err);
  870.     }

  871.     return NGX_ERROR;
  872. }


  873. static u_short *
  874. ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, size_t reserved)
  875. {
  876.     u_char    *p;
  877.     u_short   *u, *last;
  878.     uint32_t   n;

  879.     p = utf8;
  880.     u = utf16;
  881.     last = utf16 + *len;

  882.     while (u < last) {

  883.         if (*p < 0x80) {
  884.             *u++ = (u_short) *p;

  885.             if (*p == 0) {
  886.                 *len = u - utf16;
  887.                 return utf16;
  888.             }

  889.             p++;

  890.             continue;
  891.         }

  892.         if (u + 1 == last) {
  893.             *len = u - utf16;
  894.             break;
  895.         }

  896.         n = ngx_utf8_decode(&p, 4);

  897.         if (n > 0x10ffff) {
  898.             ngx_set_errno(NGX_EILSEQ);
  899.             return NULL;
  900.         }

  901.         if (n > 0xffff) {
  902.             n -= 0x10000;
  903.             *u++ = (u_short) (0xd800 + (n >> 10));
  904.             *u++ = (u_short) (0xdc00 + (n & 0x03ff));
  905.             continue;
  906.         }

  907.         *u++ = (u_short) n;
  908.     }

  909.     /* the given buffer is not enough, allocate a new one */

  910.     u = malloc(((p - utf8) + ngx_strlen(p) + 1 + reserved) * sizeof(u_short));
  911.     if (u == NULL) {
  912.         return NULL;
  913.     }

  914.     ngx_memcpy(u, utf16, *len * 2);

  915.     utf16 = u;
  916.     u += *len;

  917.     for ( ;; ) {

  918.         if (*p < 0x80) {
  919.             *u++ = (u_short) *p;

  920.             if (*p == 0) {
  921.                 *len = u - utf16;
  922.                 return utf16;
  923.             }

  924.             p++;

  925.             continue;
  926.         }

  927.         n = ngx_utf8_decode(&p, 4);

  928.         if (n > 0x10ffff) {
  929.             ngx_free(utf16);
  930.             ngx_set_errno(NGX_EILSEQ);
  931.             return NULL;
  932.         }

  933.         if (n > 0xffff) {
  934.             n -= 0x10000;
  935.             *u++ = (u_short) (0xd800 + (n >> 10));
  936.             *u++ = (u_short) (0xdc00 + (n & 0x03ff));
  937.             continue;
  938.         }

  939.         *u++ = (u_short) n;
  940.     }

  941.     /* unreachable */
  942. }


  943. static u_char *
  944. ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, size_t *allocated)
  945. {
  946.     u_char    *p, *last;
  947.     u_short   *u, *j;
  948.     uint32_t   n;

  949.     u = utf16;
  950.     p = utf8;
  951.     last = utf8 + *len;

  952.     while (p < last) {

  953.         if (*u < 0x80) {
  954.             *p++ = (u_char) *u;

  955.             if (*u == 0) {
  956.                 *len = p - utf8;
  957.                 return utf8;
  958.             }

  959.             u++;

  960.             continue;
  961.         }

  962.         if (p >= last - 4) {
  963.             *len = p - utf8;
  964.             break;
  965.         }

  966.         n = ngx_utf16_decode(&u, 2);

  967.         if (n > 0x10ffff) {
  968.             ngx_set_errno(NGX_EILSEQ);
  969.             return NULL;
  970.         }

  971.         if (n >= 0x10000) {
  972.             *p++ = (u_char) (0xf0 + (n >> 18));
  973.             *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f));
  974.             *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
  975.             *p++ = (u_char) (0x80 + (n & 0x3f));
  976.             continue;
  977.         }

  978.         if (n >= 0x0800) {
  979.             *p++ = (u_char) (0xe0 + (n >> 12));
  980.             *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
  981.             *p++ = (u_char) (0x80 + (n & 0x3f));
  982.             continue;
  983.         }

  984.         *p++ = (u_char) (0xc0 + (n >> 6));
  985.         *p++ = (u_char) (0x80 + (n & 0x3f));
  986.     }

  987.     /* the given buffer is not enough, allocate a new one */

  988.     for (j = u; *j; j++) { /* void */ }

  989.     p = malloc((j - utf16) * 4 + 1);
  990.     if (p == NULL) {
  991.         return NULL;
  992.     }

  993.     if (allocated) {
  994.         *allocated = (j - utf16) * 4 + 1;
  995.     }

  996.     ngx_memcpy(p, utf8, *len);

  997.     utf8 = p;
  998.     p += *len;

  999.     for ( ;; ) {

  1000.         if (*u < 0x80) {
  1001.             *p++ = (u_char) *u;

  1002.             if (*u == 0) {
  1003.                 *len = p - utf8;
  1004.                 return utf8;
  1005.             }

  1006.             u++;

  1007.             continue;
  1008.         }

  1009.         n = ngx_utf16_decode(&u, 2);

  1010.         if (n > 0x10ffff) {
  1011.             ngx_free(utf8);
  1012.             ngx_set_errno(NGX_EILSEQ);
  1013.             return NULL;
  1014.         }

  1015.         if (n >= 0x10000) {
  1016.             *p++ = (u_char) (0xf0 + (n >> 18));
  1017.             *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f));
  1018.             *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
  1019.             *p++ = (u_char) (0x80 + (n & 0x3f));
  1020.             continue;
  1021.         }

  1022.         if (n >= 0x0800) {
  1023.             *p++ = (u_char) (0xe0 + (n >> 12));
  1024.             *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
  1025.             *p++ = (u_char) (0x80 + (n & 0x3f));
  1026.             continue;
  1027.         }

  1028.         *p++ = (u_char) (0xc0 + (n >> 6));
  1029.         *p++ = (u_char) (0x80 + (n & 0x3f));
  1030.     }

  1031.     /* unreachable */
  1032. }


  1033. /*
  1034. * ngx_utf16_decode() decodes one or two UTF-16 code units
  1035. * the return values:
  1036. *    0x80 - 0x10ffff         valid character
  1037. *    0x110000 - 0xfffffffd   invalid sequence
  1038. *    0xfffffffe              incomplete sequence
  1039. *    0xffffffff              error
  1040. */

  1041. uint32_t
  1042. ngx_utf16_decode(u_short **u, size_t n)
  1043. {
  1044.     uint32_t  k, m;

  1045.     k = **u;

  1046.     if (k < 0xd800 || k > 0xdfff) {
  1047.         (*u)++;
  1048.         return k;
  1049.     }

  1050.     if (k > 0xdbff) {
  1051.         (*u)++;
  1052.         return 0xffffffff;
  1053.     }

  1054.     if (n < 2) {
  1055.         return 0xfffffffe;
  1056.     }

  1057.     (*u)++;

  1058.     m = *(*u)++;

  1059.     if (m < 0xdc00 || m > 0xdfff) {
  1060.         return 0xffffffff;

  1061.     }

  1062.     return 0x10000 + ((k - 0xd800) << 10) + (m - 0xdc00);
  1063. }