changeset 3435:d65ba5392f59 stable-0.7

merge r3138, r3139, r3157, r3158, r3159, r3164, r3165, r3202, r3203, r3383, r3388, r3417, r3418: Win32 (mostly) and some Unix file related fixes: *) preserve errno while ngx_free() *) win32 ngx_file_info() utf8 support *) delete Win95 code *) log file name for read/write errors *) test incomplete WriteFile() *) handle short pwrite() to log an error cause: ENOSPC, EDQUOT, or EFBIG *) uniform ngx_directio_on/off() interface with other file functions *) do not create Win32 drive letter in ngx_create_full_path() *) ignore EACCES errors for top level directories in ngx_create_full_path() *) fix Win32 error messages when an temporary file replaces an existent file: *) do not rename an already renamed file *) now ngx_win32_rename_file() returns error code *) do not log failure inside ngx_win32_rename_file() *) fix Win32 error message when an temporary file replaces an existent file: return at once if ngx_win32_rename_file() was not failed and do not try to delete already the renamed temporary file *) skip URI trailing spaces under Win32 *) disable Win32 short file names
author Igor Sysoev <igor@sysoev.ru>
date Mon, 01 Feb 2010 15:06:25 +0000
parents 8d310fbeaa38
children fc81ff0c2adc
files src/core/ngx_file.c src/core/ngx_open_file_cache.c src/core/ngx_output_chain.c src/http/ngx_http_request.c src/os/unix/ngx_files.c src/os/win32/ngx_files.c src/os/win32/ngx_files.h
diffstat 7 files changed, 176 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -183,7 +183,15 @@ ngx_create_full_path(u_char *dir, ngx_ui
     u_char     *p, ch;
     ngx_err_t   err;
 
-    for (p = dir + 1; *p; p++) {
+    err = 0;
+
+#if (NGX_WIN32)
+    p = dir + 3;
+#else
+    p = dir + 1;
+#endif
+
+    for ( /* void */ ; *p; p++) {
         ch = *p;
 
         if (ch != '/') {
@@ -194,7 +202,14 @@ ngx_create_full_path(u_char *dir, ngx_ui
 
         if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
             err = ngx_errno;
-            if (err != NGX_EEXIST) {
+
+            switch (err) {
+            case NGX_EEXIST:
+                err = 0;
+            case NGX_EACCES:
+                break;
+
+            default:
                 return err;
             }
         }
@@ -202,7 +217,7 @@ ngx_create_full_path(u_char *dir, ngx_ui
         *p = '/';
     }
 
-    return 0;
+    return err;
 }
 
 
@@ -576,16 +591,10 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 #if (NGX_WIN32)
 
     if (err == NGX_EEXIST) {
-        if (ngx_win32_rename_file(src, to, ext->log) == NGX_OK) {
+        err = ngx_win32_rename_file(src, to, ext->log);
 
-            if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
-                return NGX_OK;
-            }
-
-            err = ngx_errno;
-
-        } else {
-            err = 0;
+        if (err == 0) {
+            return NGX_OK;
         }
     }
 
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -525,7 +525,7 @@ ngx_open_and_stat_file(u_char *name, ngx
         of->fd = fd;
 
         if (of->directio <= ngx_file_size(&fi)) {
-            if (ngx_directio_on(fd) == -1) {
+            if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                               ngx_directio_on_n " \"%s\" failed", name);
 
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -510,7 +510,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
 #if (NGX_HAVE_ALIGNED_DIRECTIO)
 
         if (ctx->unaligned) {
-            if (ngx_directio_off(src->file->fd) == -1) {
+            if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
                               ngx_directio_off_n " \"%s\" failed",
                               src->file->name.data);
@@ -528,7 +528,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
 
             err = ngx_errno;
 
-            if (ngx_directio_on(src->file->fd) == -1) {
+            if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
                               ngx_directio_on_n " \"%s\" failed",
                               src->file->name.data);
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -784,9 +784,11 @@ ngx_http_process_request_line(ngx_event_
 
             p = r->uri.data + r->uri.len - 1;
 
-            if (*p == '.') {
-
-                while (--p > r->uri.data && *p == '.') { /* void */ }
+            if (*p == '.' || *p == ' ') {
+
+                while (--p > r->uri.data && (*p == '.' || *p == ' ')) {
+                    /* void */
+                }
 
                 r->uri.len = p + 1 - r->uri.data;
 
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -22,7 +22,7 @@ ngx_read_file(ngx_file_t *file, u_char *
 
     if (n == -1) {
         ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                      "pread() failed, file \"%s\"", file->name.data);
+                      "pread() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -30,7 +30,8 @@ ngx_read_file(ngx_file_t *file, u_char *
 
     if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "lseek() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
@@ -40,7 +41,8 @@ ngx_read_file(ngx_file_t *file, u_char *
     n = read(file->fd, buf, size);
 
     if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "read() failed");
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                      "read() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -57,57 +59,66 @@ ngx_read_file(ngx_file_t *file, u_char *
 ssize_t
 ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
-    ssize_t  n;
+    ssize_t  n, written;
 
     ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
                    "write: %d, %p, %uz, %O", file->fd, buf, size, offset);
 
+    written = 0;
+
 #if (NGX_HAVE_PWRITE)
 
-    n = pwrite(file->fd, buf, size, offset);
+    for ( ;; ) {
+        n = pwrite(file->fd, buf, size, offset);
+
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "pwrite() \"%s\" failed", file->name.data);
+            return NGX_ERROR;
+        }
 
-    if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pwrite() failed");
-        return NGX_ERROR;
-    }
+        file->offset += n;
+        written += n;
 
-    if ((size_t) n != size) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                      "pwrite() has written only %z of %uz", n, size);
-        return NGX_ERROR;
+        if ((size_t) n == size) {
+            return written;
+        }
+
+        offset += n;
+        size -= n;
     }
 
 #else
 
     if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "lseek() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
         file->sys_offset = offset;
     }
 
-    n = write(file->fd, buf, size);
+    for ( ;; ) {
+        n = write(file->fd, buf, size);
 
-    if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "write() failed");
-        return NGX_ERROR;
-    }
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "write() \"%s\" failed", file->name.data);
+            return NGX_ERROR;
+        }
 
-    if ((size_t) n != size) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                      "write() has written only %z of %uz", n, size);
-        return NGX_ERROR;
-    }
+        file->offset += n;
+        written += n;
 
-    file->sys_offset += n;
-
-#endif
+        if ((size_t) n == size) {
+            return written;
+        }
 
-    file->offset += n;
-
-    return n;
+        size -= n;
+    }
+#endif
 }
 
 
@@ -191,7 +202,7 @@ ngx_write_chain_to_file(ngx_file_t *file
         if (file->sys_offset != offset) {
             if (lseek(file->fd, offset, SEEK_SET) == -1) {
                 ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                              "lseek() failed");
+                              "lseek() \"%s\" failed", file->name.data);
                 return NGX_ERROR;
             }
 
@@ -202,13 +213,14 @@ ngx_write_chain_to_file(ngx_file_t *file
 
         if (n == -1) {
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                          "writev() failed");
+                          "writev() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
         if ((size_t) n != size) {
             ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                          "writev() has written only %z of %uz", n, size);
+                          "writev() \"%s\" has written only %z of %uz",
+                          file->name.data, n, size);
             return NGX_ERROR;
         }
 
@@ -393,7 +405,7 @@ ngx_directio_on(ngx_fd_t fd)
     flags = fcntl(fd, F_GETFL);
 
     if (flags == -1) {
-        return -1;
+        return NGX_FILE_ERROR;
     }
 
     return fcntl(fd, F_SETFL, flags | O_DIRECT);
@@ -408,7 +420,7 @@ ngx_directio_off(ngx_fd_t fd)
     flags = fcntl(fd, F_GETFL);
 
     if (flags == -1) {
-        return -1;
+        return NGX_FILE_ERROR;
     }
 
     return fcntl(fd, F_SETFL, flags & ~O_DIRECT);
--- a/src/os/win32/ngx_files.c
+++ b/src/os/win32/ngx_files.c
@@ -10,7 +10,7 @@
 
 #define NGX_UTF16_BUFLEN  256
 
-static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t len);
+static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len);
 
 
 /* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */
@@ -18,24 +18,60 @@ static u_short *ngx_utf8_to_utf16(u_shor
 ngx_fd_t
 ngx_open_file(u_char *name, u_long mode, u_long create, u_long access)
 {
-    u_short   *u;
-    ngx_fd_t   fd;
-    u_short    utf16[NGX_UTF16_BUFLEN];
+    size_t      len;
+    u_long      n;
+    u_short    *u, *lu;
+    ngx_fd_t    fd;
+    ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
 
-    u = ngx_utf8_to_utf16(utf16, name, NGX_UTF16_BUFLEN);
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len);
 
     if (u == NULL) {
         return INVALID_HANDLE_VALUE;
     }
 
+    fd = INVALID_HANDLE_VALUE;
+    lu = NULL;
+
+    if (create == NGX_FILE_OPEN) {
+
+        lu = malloc(len * 2);
+        if (lu == NULL) {
+            goto failed;
+        }
+
+        n = GetLongPathNameW(u, lu, len);
+
+        if (n == 0) {
+            goto failed;
+        }
+
+        if (n != len - 1 || ngx_memcmp(u, lu, n) != 0) {
+            ngx_set_errno(NGX_ENOENT);
+            goto failed;
+        }
+    }
+
     fd = CreateFileW(u, mode,
                      FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                      NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 
+failed:
+
+    err = ngx_errno;
+
+    if (lu) {
+        ngx_free(lu);
+    }
+
     if (u != utf16) {
         ngx_free(u);
     }
 
+    ngx_set_errno(err);
+
     return fd;
 }
 
@@ -43,56 +79,17 @@ ngx_open_file(u_char *name, u_long mode,
 ssize_t
 ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
-    long        high_offset;
     u_long      n;
     ngx_err_t   err;
     OVERLAPPED  ovlp, *povlp;
 
-    if (ngx_win32_version < NGX_WIN_NT) {
-
-        /*
-         * under Win9X the overlapped pointer must be NULL
-         * so we have to use SetFilePointer() to set the offset
-         */
-
-        if (file->offset != offset) {
-
-            /*
-             * the maximum file size on the FAT16 is 2G, but on the FAT32
-             * the size is 4G so we have to use the high_offset
-             * because a single offset is signed value
-             */
-
-            high_offset = (long) (offset >> 32);
+    ovlp.Internal = 0;
+    ovlp.InternalHigh = 0;
+    ovlp.Offset = (u_long) offset;
+    ovlp.OffsetHigh = (u_long) (offset >> 32);
+    ovlp.hEvent = NULL;
 
-            if (SetFilePointer(file->fd, (long) offset, &high_offset,
-                               FILE_BEGIN) == INVALID_SET_FILE_POINTER)
-            {
-                /*
-                 * INVALID_SET_FILE_POINTER is 0xffffffff and it can be valid
-                 * value for large file so we need also to check GetLastError()
-                 */
-
-                err = ngx_errno;
-                if (err != NO_ERROR) {
-                    ngx_log_error(NGX_LOG_ERR, file->log, err,
-                                  "SeekFilePointer() failed");
-                    return NGX_ERROR;
-                }
-            }
-        }
-
-        povlp = NULL;
-
-    } else {
-        ovlp.Internal = 0;
-        ovlp.InternalHigh = 0;
-        ovlp.Offset = (u_long) offset;
-        ovlp.OffsetHigh = (u_long) (offset >> 32);
-        ovlp.hEvent = NULL;
-
-        povlp = &ovlp;
-    }
+    povlp = &ovlp;
 
     if (ReadFile(file->fd, buf, size, &n, povlp) == 0) {
         err = ngx_errno;
@@ -101,7 +98,8 @@ ngx_read_file(ngx_file_t *file, u_char *
             return 0;
         }
 
-        ngx_log_error(NGX_LOG_ERR, file->log, err, "ReadFile() failed");
+        ngx_log_error(NGX_LOG_ERR, file->log, err,
+                      "ReadFile() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -114,58 +112,27 @@ ngx_read_file(ngx_file_t *file, u_char *
 ssize_t
 ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
-    long        high_offset;
     u_long      n;
-    ngx_err_t   err;
     OVERLAPPED  ovlp, *povlp;
 
-    if (ngx_win32_version < NGX_WIN_NT) {
-
-        /*
-         * under Win9X the overlapped pointer must be NULL
-         * so we have to use SetFilePointer() to set the offset
-         */
-
-        if (file->offset != offset) {
-
-            /*
-             * the maximum file size on the FAT16 is 2G, but on the FAT32
-             * the size is 4G so we have to use high_offset
-             * because a single offset is signed value
-             */
+    ovlp.Internal = 0;
+    ovlp.InternalHigh = 0;
+    ovlp.Offset = (u_long) offset;
+    ovlp.OffsetHigh = (u_long) (offset >> 32);
+    ovlp.hEvent = NULL;
 
-            high_offset = (long) (offset >> 32);
-            if (SetFilePointer(file->fd, (long) offset, &high_offset,
-                               FILE_BEGIN) == INVALID_SET_FILE_POINTER)
-            {
-                /*
-                 * INVALID_SET_FILE_POINTER is 0xffffffff and it can be valid
-                 * value for large file so we need also to check GetLastError()
-                 */
+    povlp = &ovlp;
 
-                err = ngx_errno;
-                if (err != NO_ERROR) {
-                    ngx_log_error(NGX_LOG_ERR, file->log, err,
-                                  "SeekFilePointer() failed");
-                    return NGX_ERROR;
-                }
-            }
-        }
-
-        povlp = NULL;
-
-    } else {
-        ovlp.Internal = 0;
-        ovlp.InternalHigh = 0;
-        ovlp.Offset = (u_long) offset;
-        ovlp.OffsetHigh = (u_long) (offset >> 32);
-        ovlp.hEvent = NULL;
-
-        povlp = &ovlp;
+    if (WriteFile(file->fd, buf, size, &n, povlp) == 0) {
+        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno,
+                      "WriteFile() \"%s\" failed", file->name.data);
+        return NGX_ERROR;
     }
 
-    if (WriteFile(file->fd, buf, size, &n, povlp) == 0) {
-        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "WriteFile() failed");
+    if (n != size) {
+        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
+                      "WriteFile() \"%s\" has written only %ul of %uz",
+                      file->name.data, n, size);
         return NGX_ERROR;
     }
 
@@ -253,17 +220,17 @@ ngx_write_console(ngx_fd_t fd, void *buf
 }
 
 
-ngx_int_t
+ngx_err_t
 ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log)
 {
     u_char             *name;
-    ngx_int_t           rc;
+    ngx_err_t           err;
     ngx_uint_t          collision;
     ngx_atomic_uint_t   num;
 
     name = ngx_alloc(to->len + 1 + 10 + 1 + sizeof("DELETE"), log);
     if (name == NULL) {
-        return NGX_ERROR;
+        return NGX_ENOMEM;
     }
 
     ngx_memcpy(name, to->data, to->len);
@@ -288,10 +255,10 @@ ngx_win32_rename_file(ngx_str_t *from, n
     }
 
     if (MoveFile((const char *) from->data, (const char *) to->data) == 0) {
-        rc = NGX_ERROR;
+        err = ngx_errno;
 
     } else {
-        rc = NGX_OK;
+        err = 0;
     }
 
     if (DeleteFile((const char *) name) == 0) {
@@ -299,29 +266,38 @@ ngx_win32_rename_file(ngx_str_t *from, n
                       "DeleteFile() \"%s\" failed", name);
     }
 
-    if (rc == NGX_ERROR) {
-        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
-                      "MoveFile() \"%s\" to \"%s\" failed",
-                      from->data, to->data);
-    }
-
     /* mutex_unlock() */
 
     ngx_free(name);
 
-    return rc;
+    return err;
 }
 
 
 ngx_int_t
 ngx_file_info(u_char *file, ngx_file_info_t *sb)
 {
-    WIN32_FILE_ATTRIBUTE_DATA  fa;
+    size_t                      len;
+    long                        rc;
+    u_short                    *u;
+    ngx_err_t                   err;
+    WIN32_FILE_ATTRIBUTE_DATA   fa;
+    u_short                     utf16[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+
+    u = ngx_utf8_to_utf16(utf16, file, &len);
 
-    /* NT4 and Win98 */
+    if (u == NULL) {
+        return NGX_FILE_ERROR;
+    }
 
-    if (GetFileAttributesEx((char *) file, GetFileExInfoStandard, &fa) == 0) {
-        return NGX_FILE_ERROR;
+    rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa);
+
+    if (u != utf16) {
+        err = ngx_errno;
+        ngx_free(u);
+        ngx_set_errno(err);
     }
 
     sb->dwFileAttributes = fa.dwFileAttributes;
@@ -331,7 +307,7 @@ ngx_file_info(u_char *file, ngx_file_inf
     sb->nFileSizeHigh = fa.nFileSizeHigh;
     sb->nFileSizeLow = fa.nFileSizeLow;
 
-    return ~NGX_FILE_ERROR;
+    return rc;
 }
 
 
@@ -533,14 +509,14 @@ ngx_de_link_info(u_char *name, ngx_dir_t
 ngx_int_t
 ngx_directio_on(ngx_fd_t fd)
 {
-    return 0;
+    return ~NGX_FILE_ERROR;
 }
 
 
 ngx_int_t
 ngx_directio_off(ngx_fd_t fd)
 {
-    return 0;
+    return ~NGX_FILE_ERROR;
 }
 
 
@@ -564,7 +540,7 @@ ngx_fs_bsize(u_char *name)
 
 
 static u_short *
-ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t len)
+ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len)
 {
     u_char    *p;
     u_short   *u, *last;
@@ -572,18 +548,18 @@ ngx_utf8_to_utf16(u_short *utf16, u_char
 
     p = utf8;
     u = utf16;
-    last = utf16 + len;
+    last = utf16 + *len;
 
     while (u < last) {
 
         if (*p < 0x80) {
-            *u = (u_short) *p;
+            *u++ = (u_short) *p;
 
             if (*p == 0) {
+                *len = u - utf16;
                 return utf16;
             }
 
-            u++;
             p++;
 
             continue;
@@ -607,21 +583,21 @@ ngx_utf8_to_utf16(u_short *utf16, u_char
         return NULL;
     }
 
-    ngx_memcpy(u, utf16, len * 2);
+    ngx_memcpy(u, utf16, *len * 2);
 
     utf16 = u;
-    u += len;
+    u += *len;
 
     for ( ;; ) {
 
         if (*p < 0x80) {
-            *u = (u_short) *p;
+            *u++ = (u_short) *p;
 
             if (*p == 0) {
+                *len = u - utf16;
                 return utf16;
             }
 
-            u++;
             p++;
 
             continue;
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -111,7 +111,7 @@ ssize_t ngx_write_console(ngx_fd_t fd, v
 
 #define ngx_rename_file(o, n)       MoveFile((const char *) o, (const char *) n)
 #define ngx_rename_file_n           "MoveFile()"
-ngx_int_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log);
+ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log);