changeset 74:17ab1af8c3dd

nginx-0.0.1-2003-04-11-20:01:14 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 11 Apr 2003 16:01:14 +0000
parents 4534060fde92
children 869b10be682f
files src/core/ngx_file.c src/core/ngx_file.h src/core/ngx_hunk.h src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_static_handler.c src/http/modules/proxy/ngx_http_event_proxy_handler.c src/http/modules/proxy/ngx_http_event_proxy_handler.h src/http/ngx_http.h src/http/ngx_http_core_module.c src/os/unix/ngx_errno.h src/os/unix/ngx_files.c src/os/unix/ngx_files.h src/os/unix/ngx_freebsd_write_chain.c src/os/unix/ngx_recv_chain.c src/os/win32/ngx_errno.h src/os/win32/ngx_files.h
diffstat 16 files changed, 498 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/ngx_file.c	Fri Apr 11 16:01:14 2003 +0000
@@ -0,0 +1,140 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_hunk.h>
+#include <ngx_array.h>
+#include <ngx_file.h>
+#include <ngx_files.h>
+
+
+int ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
+                         ngx_pool_t *pool, int num, int step, int persistent)
+{
+    int        i;
+    ngx_err_t  err;
+
+    file->name.len = path->name.len + 1 + path->len + 10;
+
+    ngx_test_null(file->name.data, ngx_palloc(pool, file->name.len + 1),
+                  NGX_ERROR);
+
+#if 0
+    for (i = 0; i < file->name.len; i++) {
+         file->name.data[i] = 'X';
+    }
+#endif
+
+    ngx_memcpy(file->name.data, path->name.data, path->name.len);
+
+    for ( ;; ) {
+        snprintf(file->name.data + path->name.len + 1 + path->len, 11,
+                 "%010d", num);
+
+        ngx_create_hashed_filename(file, path);
+
+#if 0
+#if (WIN32)
+        file->fd = CreateFile(file->name.data,
+                        GENERIC_READ|GENERIC_WRITE,
+                        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                        NULL,
+                        CREATE_NEW,
+                        persistent ? 0:
+                            FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,
+                        NULL);
+#else
+        file->fd = open(file->name.data, O_CREAT|O_EXCL|O_WRONLY, 0600);
+#endif
+#endif
+
+        file->fd = ngx_open_tempfile(file->name.data, persistent);
+
+        if (file->fd != NGX_INVALID_FILE) {
+            return NGX_OK;
+        }
+
+        err = ngx_errno;
+
+        if (err == NGX_EEXIST) {
+            num *= step;
+            continue;
+        }
+
+        if (err != NGX_ENOENT
+#if (WIN32_NEED_TEST)
+            && err != NGX_ENOTDIR
+#endif
+        ) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, err,
+                          ngx_open_tempfile_n " \"%s\" failed",
+                          file->name.data);
+            return NGX_ERROR;
+        }
+
+        if (ngx_create_path(file, path) == NGX_ERROR) {
+            return NGX_ERROR;
+        }        
+    }
+}
+
+
+void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path)
+{
+    int        i, name, pos, level;
+
+    name = file->name.len;
+    pos = path->name.len + 1;
+
+    file->name.data[path->name.len + path->len]  = '/';
+
+    for (i = 0; i < 3; i++) {
+        level = path->level[i];
+
+        if (level == 0) {
+            break;
+        }
+
+        ngx_log_debug(file->log, "temp: %s" _ file->name.data);
+
+        name -= level;
+        file->name.data[pos - 1] = '/';
+        ngx_memcpy(&file->name.data[pos], &file->name.data[name], level);
+        pos += level + 1;
+    }
+
+    ngx_log_debug(file->log, "temp: %s" _ file->name.data);
+}
+
+
+int ngx_create_path(ngx_file_t *file, ngx_path_t *path)
+{
+    int        i, pos;
+    ngx_err_t  err;
+
+    pos = path->name.len;
+
+    for (i = 0; i < 3; i++) {
+        if (path->level[i] == 0) {
+            break;
+        }
+
+        pos += path->level[i] + 1;
+
+        file->name.data[pos] = '\0';
+
+        ngx_log_debug(file->log, "temp: %s" _ file->name.data);
+
+        if (ngx_mkdir(file->name.data) == NGX_FILE_ERROR) {
+            err = ngx_errno;
+            if (err != NGX_EEXIST) {
+                ngx_log_error(NGX_LOG_CRIT, file->log, err,
+                              ngx_mkdir_n " \"%s\" failed", file->name.data);
+                return NGX_ERROR;
+            }
+        }
+
+        file->name.data[pos] = '/';
+    }
+
+    return NGX_OK;
+}
--- a/src/core/ngx_file.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/core/ngx_file.h	Fri Apr 11 16:01:14 2003 +0000
@@ -4,6 +4,7 @@
 
 #include <ngx_file.h>
 #include <ngx_log.h>
+#include <ngx_alloc.h>
 #include <ngx_string.h>
 
 typedef struct ngx_file_s  ngx_file_t;
@@ -21,4 +22,18 @@
 };
 
 
+typedef struct {
+    ngx_str_t  name;
+    int        len;
+    int        level[3];
+} ngx_path_t;
+
+
+int ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
+                         ngx_pool_t *pool, int num, int step, int persistent);
+void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path);
+int ngx_create_path(ngx_file_t *file, ngx_path_t *path);
+
+
+
 #endif /* _NGX_FILE_H_INCLUDED_ */
--- a/src/core/ngx_hunk.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/core/ngx_hunk.h	Fri Apr 11 16:01:14 2003 +0000
@@ -34,20 +34,8 @@
 
 
 
-
 typedef struct ngx_hunk_s ngx_hunk_t;
 struct ngx_hunk_s {
-#if 0
-    union {
-        char    *mem;           /* start of current data */
-        off_t    file;   
-    } pos;
-    union {
-        char    *mem;           /* end of current data */
-        off_t    file;   
-    } last;
-#endif
-
     char        *pos;
     char        *last;
     off_t        file_pos;
@@ -60,10 +48,10 @@
     char        *post_end;      /* end of post-allocated hunk */
     int          tag;
     ngx_file_t  *file;
+    ngx_hunk_t  *shadow;
 };
 
 
-
 typedef struct ngx_chain_s  ngx_chain_t;
 struct ngx_chain_s {
     ngx_hunk_t  *hunk;
--- a/src/http/modules/ngx_http_index_handler.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/http/modules/ngx_http_index_handler.c	Fri Apr 11 16:01:14 2003 +0000
@@ -58,8 +58,9 @@
    Try to open first index file before the test of the directory existence
    because the valid requests should be many more then invalid ones.
    If open() failed then stat() should be more quickly because some data
-   is already cached in the kernel.  Besides Win32 has ERROR_PATH_NOT_FOUND
-   and Unix has ENOTDIR error (although it less helpfull).
+   is already cached in the kernel.
+   Besides Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR) and
+   Unix has ENOTDIR error (although it less helpfull).
 */
 
 int ngx_http_index_handler(ngx_http_request_t *r)
@@ -110,11 +111,7 @@
 ngx_log_error(NGX_LOG_DEBUG, r->connection->log, err,
               "DEBUG: " ngx_open_file_n " %s failed", name);
 
-#if (WIN32)
-            if (err == ERROR_PATH_NOT_FOUND) {
-#else
             if (err == NGX_ENOTDIR) {
-#endif
                 r->path_not_found = 1;
 
             } else if (err == NGX_EACCES) {
--- a/src/http/modules/ngx_http_static_handler.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/http/modules/ngx_http_static_handler.c	Fri Apr 11 16:01:14 2003 +0000
@@ -40,14 +40,15 @@
                       "ngx_http_static_handler: "
                       ngx_open_file_n " %s failed", r->file.name.data);
 
-        if (err == NGX_ENOENT)
+        if (err == NGX_ENOENT) {
+            return NGX_HTTP_NOT_FOUND;
+
+        } else if (err == NGX_ENOTDIR) {
             return NGX_HTTP_NOT_FOUND;
-#if (WIN32)
-        else if (err == ERROR_PATH_NOT_FOUND)
-            return NGX_HTTP_NOT_FOUND;
-#endif
-        else
+
+        } else {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
     }
 
     if (!r->file.info_valid) {
--- a/src/http/modules/proxy/ngx_http_event_proxy_handler.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/http/modules/proxy/ngx_http_event_proxy_handler.c	Fri Apr 11 16:01:14 2003 +0000
@@ -31,6 +31,9 @@
 static int ngx_http_proxy_process_upstream_header_line(ngx_http_proxy_ctx_t *p);
 
 
+static int ngx_http_proxy_write_upstream_body(ngx_event_t *wev);
+
+
 static int ngx_http_proxy_read_response_body(ngx_event_t *ev);
 static int ngx_http_proxy_write_to_client(ngx_event_t *ev);
 
@@ -39,6 +42,7 @@
 static int ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int error);
 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len);
 
+static int ngx_http_proxy_init(ngx_pool_t *pool);
 static void *ngx_http_proxy_create_loc_conf(ngx_pool_t *pool);
 
 static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -82,7 +86,7 @@
     &ngx_http_proxy_module_ctx,            /* module context */
     ngx_http_proxy_commands,               /* module directives */
     NGX_HTTP_MODULE_TYPE,                  /* module type */
-    NULL                                   /* init module */
+    ngx_http_proxy_init                    /* init module */
 };
 
 
@@ -179,7 +183,7 @@
     }
 
     /* TODO: duplicate the hunks and chain if there is backend farm */
-    p->out = chain;
+    p->request_hunks = chain;
 
     p->last_error = NGX_HTTP_BAD_GATEWAY;
     ngx_http_proxy_process_upstream(p, NULL);
@@ -679,12 +683,12 @@
     ngx_chain_t  *chain;
     ngx_event_t  *wev;
 
-    chain = ngx_write_chain(p->connection, p->out, 0);
+    chain = ngx_write_chain(p->connection, p->request_hunks, 0);
     if (chain == (ngx_chain_t *) -1) {
         return NGX_ERROR;
     }
 
-    p->out = chain;
+    p->request_hunks = chain;
 
     wev = p->connection->write;
 
@@ -1026,12 +1030,11 @@
 }
 
 
-#if 0
-
 static int ngx_http_proxy_read_upstream_body(ngx_event_t *rev)
 {
+    int                    rc, n, size;
     ngx_hunk_t            *h;
-    ngx_chain_t           *chain, ce;
+    ngx_chain_t           *chain, chain_entry, *ce, *te;
     ngx_connection_t      *c;
     ngx_http_request_t    *r;
     ngx_http_proxy_ctx_t  *p;
@@ -1041,9 +1044,9 @@
     p = (ngx_http_proxy_ctx_t *)
                          ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
 
-    ce.next = NULL;
+    chain_entry.next = NULL;
 
-    do {
+    for ( ;; ) {
 
 #if (USE_KQUEUE)
 
@@ -1051,7 +1054,7 @@
             break;
         }
 
-#elif (HAVE_KQUEUE)
+#elif (HAVE_KQUEUE0)
 
         if (ngx_event_type == NGX_HAVE_KQUEUE_EVENT
             && ev->eof && ev->available == 0)
@@ -1063,6 +1066,7 @@
 
         if (p->free_hunks) {
             chain = p->free_hunks;
+            p->free_hunks = NULL;
 
         } else if (p->allocated < p->lcf->max_block_size) {
             ngx_test_null(h,
@@ -1070,12 +1074,13 @@
                           NGX_ERROR);
 
             p->allocated += p->block_size;
-            ce.hunk = h;
-            chain = &ce;
+            chain_entry.hunk = h;
+            chain = &chain_entry;
 
         } else {
-            if (p->temp_fd == NGX_INVALID_FILE) {
-                rc = ngx_create_temp_file(p->temp_file, r->cachable);
+            if (p->temp_file->fd == NGX_INVALID_FILE) {
+                rc = ngx_create_temp_file(p->temp_file, p->lcf->temp_path,
+                                          r->pool, 0, 2, r->cachable);
 
                 if (rc != NGX_OK) {
                     return rc;
@@ -1089,70 +1094,169 @@
             }
 
             n = ngx_write_chain_to_file(p->temp_file, p->in_hunks,
-                                        p->temp_offset);
+                                        p->temp_offset, r->pool);
 
             if (n == NGX_ERROR) {
                 return NGX_ERROR;
             }
 
-            ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
-                          NGX_ERROR);
+            for (ce = p->in_hunks; ce; ce = ce->next) {
+                ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
+                              NGX_ERROR);
 
-            h->type = NGX_HUNK_FILE
-                      |NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP|NGX_HUNK_RECYCLED;
+                h->type = NGX_HUNK_FILE
+                          |NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY|NGX_HUNK_RECYCLED;
 
-            h->file_pos = p->temp_offset;
-            p->temp_offset += n;
-            h->file_last = p->temp_offset;
+                ce->hunk->shadow = h;
+                h->shadow = ce->hunk;
 
-            h->file->fd = p->temp_file.fd;
-            h->file->log = p->log;
+                h->file_pos = p->temp_offset;
+                p->temp_offset += ce->hunk->last - ce->hunk->pos;
+                h->file_last = p->temp_offset;
+
+                h->file->fd = p->temp_file->fd;
+                h->file->log = p->log;
 
-            h->pos = p->in_hunks->hunk->pos;
-            h->last = p->in_hunks->hunk->last;
-            h->start = p->in_hunks->hunk->start;
-            h->end = p->in_hunks->hunk->end;
-            h->pre_start = p->in_hunks->hunk->pre_start;
-            h->post_end = p->in_hunks->hunk->post_end;
+                h->pos = ce->hunk->pos;
+                h->last = ce->hunk->last;
+                h->start = ce->hunk->start;
+                h->end = ce->hunk->end;
+                h->pre_start = ce->hunk->pre_start;
+                h->post_end = ce->hunk->post_end;
 
-            ngx_add_hunk_to_chain(p->last_out_hunk, h, r->pool, NGX_ERROR);
+                ngx_test_null(te, ngx_create_chain_entry(r->pool), NGX_ERROR);
+                te->hunk = h;
+                te->next = NULL;
 
-            ce.hunk = p->in_hunks->next;
-            p->in_hunks = p->in_hunks->next;
-            chain = &ce;
+                if (p->last_out_hunk) {
+                    p->last_out_hunk->next = te;
+                    p->last_out_hunk = te;
+
+                } else {
+                    p->last_out_hunk = te;
+                }
+            }
         }
 
         n = ngx_recv_chain(c, chain);
 
-        h->last += n;
-        left = hunk->end - hunk->last;
+        if (n == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        if (n == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        if (n == 0) {
+            break;
+        }
+
+        for (ce = chain; ce && n > 0; ce = ce->next) {
+            ngx_test_null(te, ngx_create_chain_entry(r->pool), NGX_ERROR);
+            te->hunk = ce->hunk;
+            te->next = NULL;
+
+            if (p->last_in_hunk) {
+                p->last_in_hunk->next = te;
+                p->last_in_hunk = te;
+
+            } else {
+                p->last_in_hunk = te;
+            }
+
+            size = ce->hunk->end - ce->hunk->last;
 
-    } while (n > 0 && left == 0);
+            if (n >= size) {
+                n -= size;
+                ce->hunk->last = ce->hunk->end;
+                if (ce->hunk->shadow) {
+                    ce->hunk->shadow->type &= ~(NGX_HUNK_TEMP
+                                                |NGX_HUNK_IN_MEMORY
+                                                |NGX_HUNK_RECYCLED);
+                    ce->hunk->shadow->shadow = NULL;
+
+                }
+
+                continue;
+            }
+
+            ce->hunk->last += n;
+            if (ce->hunk->shadow) {
+                ce->hunk->shadow->type &= ~(NGX_HUNK_TEMP
+                                            |NGX_HUNK_IN_MEMORY
+                                            |NGX_HUNK_RECYCLED);
+                ce->hunk->shadow->shadow = NULL;
+            }
+
+            break;
+        }
+
+        if (ce) {
+            ce->next = p->free_hunks;
+            p->free_hunks = ce;
+            break;
+
+            return NGX_OK;
+        }
+    }
 
     if (p->out_hunks && p->request->connection->write->ready) {
-        ngx_http_proxy_write_upstream_body(p->request->connection->write);
+        return
+             ngx_http_proxy_write_upstream_body(p->request->connection->write);
     }
+
+    return NGX_OK;
 }
 
 
 static int ngx_http_proxy_write_upstream_body(ngx_event_t *wev)
 {
-    while (out) {
-        output_filter(r, hunk);
-        if (again)
-            return
+    int                    rc;
+    ngx_hunk_t            *h, *sh;
+    ngx_chain_t           *ce;
+    ngx_connection_t      *c;
+    ngx_http_request_t    *r;
+    ngx_http_proxy_ctx_t  *p;
+
+    c = (ngx_connection_t *) wev->data;
+    r = (ngx_http_request_t *) c->data;
+    p = (ngx_http_proxy_ctx_t *)
+                         ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
+
+    while (p->out_hunks) {
+        h = p->out_hunks->hunk;
+        rc = ngx_http_output_filter(r, h);
+
+        if (rc == NGX_ERROR) {
+            return NGX_ERROR;
+        }
 
-        if (hunk done)
-            remove from out
-            if (hunk is memory)
-                add it to free
+        if (rc == NGX_AGAIN || h->pos < h->last) {
+            return NGX_AGAIN;
+        }
+
+        p->out_hunks = p->out_hunks->next;
+
+        /* if the complete hunk has a shadow hunk
+           then add a shadow hunk to p->free_hunks chain */
+
+        sh = h->shadow;
+
+        if (sh) {
+            sh->pos = sh->last = sh->start;
+            ngx_test_null(ce, ngx_create_chain_entry(r->pool), NGX_ERROR);
+            ce->hunk = sh;
+            ce->next = p->free_hunks;
+            p->free_hunks = ce;
+        }
     }
+
+    return NGX_OK;
 }
 
 
 
-#endif
-
 
 
 
@@ -1482,9 +1586,36 @@
 }
 
 
+static int ngx_http_proxy_init(ngx_pool_t *pool)
+{
+    int         i;
+    ngx_file_t  file;
+    ngx_path_t  path;
+
+    file.log = pool->log;
+
+    path.name.data = "temp";
+    path.name.len = 4;
+    path.level[0] = 1;
+    path.level[1] = 2;
+    path.level[2] = 3;
+    path.len = 0;
+
+    for (i = 0; i < 3; i++) {
+        if (path.level[i] == 0) {
+            break;
+        }
+        path.len += path.level[i] + 1;
+    }
+
+    return ngx_create_temp_file(&file, &path, pool, 123456789, 2, 0);
+}
+
+
 static void *ngx_http_proxy_create_loc_conf(ngx_pool_t *pool)
 {
-    ngx_http_proxy_loc_conf_t *conf;
+    int                         i;
+    ngx_http_proxy_loc_conf_t  *conf;
 
     ngx_test_null(conf,
                   ngx_pcalloc(pool, sizeof(ngx_http_proxy_loc_conf_t)),
@@ -1498,6 +1629,22 @@
     conf->header_size = 1024;
     conf->block_size = 4096;
     conf->max_block_size = 32768;
+
+    ngx_test_null(conf->temp_path, ngx_pcalloc(pool, sizeof(ngx_path_t)), NULL);
+
+    conf->temp_path->name.data = "temp";
+    conf->temp_path->name.len = 4;
+    conf->temp_path->level[0] = 1;
+    conf->temp_path->level[1] = 2;
+    conf->temp_path->level[2] = 3;
+    conf->temp_path->len = 0;
+
+    for (i = 0; i < 3; i++) {
+        if (conf->temp_path->level[i] == 0) {
+            break;
+        }
+        conf->temp_path->len += conf->temp_path->level[i] + 1;
+    }
     /**/
 
     return conf;
--- a/src/http/modules/proxy/ngx_http_event_proxy_handler.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/http/modules/proxy/ngx_http_event_proxy_handler.h	Fri Apr 11 16:01:14 2003 +0000
@@ -71,6 +71,9 @@
     int   block_size;
     int   max_block_size;
 
+    ngx_path_t  *temp_path;
+    int   temp_file_warn;
+
     int   retry_500_error;
 
 } ngx_http_proxy_loc_conf_t;
@@ -91,7 +94,26 @@
 typedef struct ngx_http_proxy_ctx_s  ngx_http_proxy_ctx_t;
 
 struct ngx_http_proxy_ctx_s {
-    ngx_chain_t  *out;
+    ngx_chain_t   *in_hunks;
+    ngx_chain_t   *last_in_hunk;
+
+    ngx_chain_t   *out_hunks;
+    ngx_chain_t   *last_out_hunk;
+
+    ngx_chain_t   *free_hunks;
+
+    ngx_chain_t   *request_hunks;
+
+    ngx_connection_t               *connection;
+    ngx_http_request_t             *request;
+    ngx_http_proxy_headers_in_t     headers_in;
+
+
+    int           block_size;
+    int           allocated;
+
+    ngx_file_t   *temp_file;
+    off_t         temp_offset;
 
     int           last_hunk;
     ngx_array_t   hunks;
@@ -99,10 +121,6 @@
 
     int           hunk_n;
 
-    ngx_connection_t               *connection;
-    ngx_http_request_t             *request;
-    ngx_http_proxy_headers_in_t     headers_in;
-
     ngx_http_proxy_upstream_url_t  *upstream_url;
     ngx_http_proxy_upstreams_t     *upstreams;
     int                             cur_upstream;
--- a/src/http/ngx_http.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/http/ngx_http.h	Fri Apr 11 16:01:14 2003 +0000
@@ -148,6 +148,7 @@
     int         path_err;
 
     unsigned  proxy:1;
+    unsigned  cachable:1;
     unsigned  pipeline:1;
     unsigned  keepalive:1;
     unsigned  lingering_close:1;
--- a/src/http/ngx_http_core_module.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/http/ngx_http_core_module.c	Fri Apr 11 16:01:14 2003 +0000
@@ -370,12 +370,12 @@
         err = ngx_errno;
         ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
                       "ngx_http_core_translate_handler: "
-                      ngx_file_type_n " %s failed", r->file.name.data);
+                      ngx_file_type_n " \"%s\" failed", r->file.name.data);
 
         if (err == NGX_ENOENT) {
             return NGX_HTTP_NOT_FOUND;
 
-        } else if (err == ERROR_PATH_NOT_FOUND) {
+        } else if (err == NGX_ENOTDIR) {
             return NGX_HTTP_NOT_FOUND;
 
         } else if (err == NGX_EACCES) {
@@ -396,17 +396,14 @@
         err = ngx_errno;
         ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
                       "ngx_http_core_handler: "
-                      ngx_open_file_n " %s failed", r->file.name.data);
+                      ngx_open_file_n " \"%s\" failed", r->file.name.data);
 
         if (err == NGX_ENOENT) {
             return NGX_HTTP_NOT_FOUND;
-#if (WIN32)
-        } else if (err == ERROR_PATH_NOT_FOUND) {
-            return NGX_HTTP_NOT_FOUND;
-#else
+
         } else if (err == NGX_ENOTDIR) {
             return NGX_HTTP_NOT_FOUND;
-#endif
+
         } else if (err == NGX_EACCES) {
             return NGX_HTTP_FORBIDDEN;
 
@@ -419,12 +416,13 @@
         if (ngx_stat_fd(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                           "ngx_http_core_handler: "
-                          ngx_stat_fd_n " %s failed", r->file.name.data);
+                          ngx_stat_fd_n " \"%s\" failed", r->file.name.data);
 
             if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                               "ngx_http_core_handler: "
-                              ngx_close_file_n " %s failed", r->file.name.data);
+                              ngx_close_file_n " \"%s\" failed",
+                              r->file.name.data);
             }
 
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -441,7 +439,7 @@
         if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                           "ngx_http_core_handler: "
-                          ngx_close_file_n " %s failed", r->file.name.data);
+                          ngx_close_file_n " \"%s\" failed", r->file.name.data);
         }
 #endif
 
@@ -487,12 +485,12 @@
 
             if (rc == NGX_HTTP_NOT_FOUND) {
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, r->path_err,
-                              "%s is not found", r->path.data);
+                              "\"%s\" is not found", r->path.data);
             }
 
             if (rc == NGX_HTTP_FORBIDDEN) {
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, r->path_err,
-                          "%s is forbidden", r->path.data);
+                          "\"%s\" is forbidden", r->path.data);
             }
 
             return rc;
@@ -501,7 +499,7 @@
 
     r->path.data[r->path.len] = '\0';
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "directory index of %s is forbidden", r->path.data);
+                  "directory index of \"%s\" is forbidden", r->path.data);
 
     return NGX_HTTP_FORBIDDEN;
 }
@@ -550,7 +548,7 @@
     if (r->file.fd != NGX_INVALID_FILE) {
         if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
-                          ngx_close_file_n " failed");
+                          ngx_close_file_n " \"%s\" failed", r->file.name.data);
         }
     }
 
--- a/src/os/unix/ngx_errno.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/unix/ngx_errno.h	Fri Apr 11 16:01:14 2003 +0000
@@ -10,6 +10,7 @@
 #define NGX_ENOENT        ENOENT
 #define NGX_EINTR         EINTR
 #define NGX_EACCES        EACCES
+#define NGX_EEXIST        EEXIST 
 #define NGX_ENOTDIR       ENOTDIR
 #define NGX_EAGAIN        EWOULDBLOCK
 #define NGX_EINPROGRESS   EINPROGRESS
--- a/src/os/unix/ngx_files.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/unix/ngx_files.c	Fri Apr 11 16:01:14 2003 +0000
@@ -1,7 +1,11 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_hunk.h>
+#include <ngx_array.h>
 #include <ngx_file.h>
+#include <ngx_files.h>
+
 
 ssize_t ngx_read_file(ngx_file_t *file, char *buf, size_t size, off_t offset)
 {
@@ -12,7 +16,7 @@
     n = pread(file->fd, buf, size, offset);
 
     if (n == -1) {
-        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "pread() failed");
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pread() failed");
         return NGX_ERROR;
     }
 
@@ -29,13 +33,66 @@
     n = pwrite(file->fd, buf, size, offset);
 
     if (n == -1) {
-        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "pwrite() failed");
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pwrite() failed");
+        return NGX_ERROR;
+    }
+
+    if ((size_t) n != size) {
+        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
+                      "pwrite() has written only %d of %d", n, size);
         return NGX_ERROR;
     }
 
-    if (n != size) {
-        ngx_log_error(NGX_LOG_ERR, file->log, 0,
-                      "pwrite() has written only %d of %d", n, size);
+    file->offset += n;
+
+    return n;
+}
+
+
+ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce,
+                                off_t offset, ngx_pool_t *pool)
+{
+    size_t         size;
+    ssize_t        n;
+    struct iovec  *iov;
+    ngx_err_t      err;
+    ngx_array_t    io;
+
+    /* use pwrite() if there's the only hunk in a chain */
+
+    if (ce->next == NULL) {
+        return ngx_write_file(file, ce->hunk->pos,
+                              ce->hunk->last - ce->hunk->pos, offset);
+    }
+
+    ngx_init_array(io, pool, 10, sizeof(struct iovec), NGX_ERROR);
+    size = 0;
+
+    while (ce) {
+        ngx_test_null(iov, ngx_push_array(&io), NGX_ERROR);
+        iov->iov_base = ce->hunk->pos;
+        iov->iov_len = ce->hunk->last - ce->hunk->pos;
+        size += ce->hunk->last - ce->hunk->pos;
+        ce = ce->next;
+    }
+
+    if (lseek(file->fd, offset, SEEK_SET) == -1) {
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+        return NGX_ERROR;
+    }
+
+    n = writev(file->fd, (struct iovec *) io.elts, io.nelts);
+
+    ngx_destroy_array(&io);
+
+    if (n == -1) {
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "writev() failed");
+        return NGX_ERROR;
+    }
+
+    if ((size_t) n != size) {
+        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
+                      "writev() has written only %d of %d", n, size);
         return NGX_ERROR;
     }
 
--- a/src/os/unix/ngx_files.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/unix/ngx_files.h	Fri Apr 11 16:01:14 2003 +0000
@@ -5,6 +5,8 @@
 #include <ngx_config.h>
 
 #include <ngx_types.h>
+#include <ngx_alloc.h>
+#include <ngx_hunk.h>
 #include <ngx_file.h>
 
 
@@ -19,11 +21,24 @@
 #define ngx_close_file           close
 #define ngx_close_file_n         "close()"
 
+#define ngx_open_tempfile(name, persistent)                                 \
+                                 open(name, O_CREAT|O_EXCL|O_WRONLY, 0600)
+#define ngx_open_tempfile_n      "open()"
+
 ssize_t ngx_read_file(ngx_file_t *file, char *buf, size_t size, off_t offset);
 #define ngx_read_file_n          "read()"
 
 #define NGX_FILE_RDONLY          O_RDONLY
 
+ssize_t ngx_write_file(ngx_file_t *file, char *buf, size_t size, off_t offset);
+
+ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce,
+                                off_t offset, ngx_pool_t *pool);
+
+
+#define ngx_mkdir(name)          mkdir(name, 0700)
+#define ngx_mkdir_n              "mkdir()"
+
 
 #define ngx_file_type(file, sb)  stat(file, sb)
 #define ngx_file_type_n          "stat()"
--- a/src/os/unix/ngx_freebsd_write_chain.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/unix/ngx_freebsd_write_chain.c	Fri Apr 11 16:01:14 2003 +0000
@@ -140,7 +140,7 @@
 
     c->sent += sent;
 
-    for (ce = in; ce; ce = ce->next) {
+    for (ce = in; ce && sent > 0; ce = ce->next) {
 
         if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
             size = ce->hunk->last - ce->hunk->pos;
--- a/src/os/unix/ngx_recv_chain.c	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/unix/ngx_recv_chain.c	Fri Apr 11 16:01:14 2003 +0000
@@ -8,10 +8,10 @@
 
 ssize_t ngx_recv_chain(ngx_connection_t *c, ngx_chain_t *ce)
 {
-    int              n;
-    struct iovec   *iov;
-    ngx_err_t       err;
-    ngx_array_t     io;
+    ssize_t         n;
+    struct iovec  *iov;
+    ngx_err_t      err;
+    ngx_array_t    io;
 
     ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_ERROR);
 
--- a/src/os/win32/ngx_errno.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/win32/ngx_errno.h	Fri Apr 11 16:01:14 2003 +0000
@@ -12,6 +12,8 @@
 
 #define NGX_ENOENT        ERROR_FILE_NOT_FOUND
 #define NGX_EACCES        ERROR_ACCESS_DENIED
+#define NGX_EEXIST        ERROR_FILE_EXISTS
+#define NGX_ENOTDIR       ERROR_PATH_NOT_FOUND
 #define NGX_EAGAIN        WSAEWOULDBLOCK
 #define NGX_EINPROGRESS   WSAEINPROGRESS
 #define NGX_EADDRINUSE    WSAEADDRINUSE
--- a/src/os/win32/ngx_files.h	Thu Apr 10 15:08:54 2003 +0000
+++ b/src/os/win32/ngx_files.h	Fri Apr 11 16:01:14 2003 +0000
@@ -26,6 +26,17 @@
                        NULL, OPEN_EXISTING, 0, NULL)
 */
 
+#define ngx_open_tempfile(name, persistent)                                 \
+            CreateFile(name,                                                \
+                    GENERIC_READ|GENERIC_WRITE,                             \
+                    FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,     \
+                    NULL,                                                   \
+                    CREATE_NEW,                                             \
+                    persistent ? 0:                                         \
+                        FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, \
+                    NULL);
+
+
 #define ngx_open_file_n             "CreateFile()"
 
 #define NGX_FILE_RDONLY             GENERIC_READ
@@ -33,6 +44,9 @@
 #define ngx_close_file              CloseHandle
 #define ngx_close_file_n            "CloseHandle()"
 
+#define ngx_mkdir(name)             CreateDirectory(name, NULL)
+#define ngx_mkdir_n                 "CreateDirectory()"
+
 int ngx_file_type(char *filename, ngx_file_info_t *fi);
 #define ngx_file_type_n             "GetFileAttributes"