[PATCH] implemented hardlink option in DAV module

Maxim Dounin mdounin at mdounin.ru
Tue Oct 16 17:48:21 UTC 2012


Hello!

On Tue, Oct 16, 2012 at 09:31:13PM +0400, Михаил Монашёв wrote:

> Здравствуйте, Maxim.
> 
> Вы писали 16 октября 2012 г., 21:10:52:
> 
> > Hello!
> 
> > On Tue, Oct 16, 2012 at 02:16:53PM +0400, Maxim Dounin wrote:
> 
> >> Hello!
> >> 
> >> On Tue, Oct 16, 2012 at 12:14:38AM +0400, Михаил Монашёв wrote:
> >> 
> >> > Здравствуйте, Gena.
> >> > 
> >> > >> У  меня, например, есть следующая задача: обновить mtime у файла по
> >> > >> вебдаву.  Т.е.  сделать  touch  файлу.  Сейчас я это делаю через Ж:
> >> > >> копирую  файл,  а  потом  мувлю его в уже существующий. Копирование
> >> > >> очень долго работает, а со ссылкой работало бы моментально.
> >> > 
> >> > > моментально  это  работало  бы,  если  добавить  к реализации WebDAV
> >> > > расширение, новый метод TOUCH который будет менять mtime файла
> >> > 
> >> > Ну  это  совсем  идеальный случай. Я о таком только мечтать могу. Если
> >> > кто-то  вдруг  реализует,  то  я  только  за.  А пока выкручиваюсь как
> >> > получается.
> >> 
> >> Если следовать идеалогии WebDAV'а, то твоя задача должна решаться 
> >> с помощью метода PROPPATCH[1].  Но он долбанутый на всю голову и 
> >> там требуется, чтобы сервер занимался парсингом набора инструкций 
> >> в XML'е.
> >> 
> >> Если следовать здравому смыслу - то TOUCH, конечно, будет 
> >> существенно проще.  Единственное что останавливает - его 
> >> отсутствие, т.е. полная и абсолютная неспецифицированность.  С 
> >> идеалогической точки зрения - возможно тут подойдёт правильно 
> >> применённый метод PATCH[2].
> >> 
> >> Использование COPY с hardlink'ами для решения подобной задачи - 
> >> это как-то слишком, IMHO, полностью согласен с Геной.  (Я бы 
> >> наверное применил тут встроенный перл и не мучился особо.)
> >> 
> >> [1] http://tools.ietf.org/html/rfc4918#section-9.2
> >> [2] http://tools.ietf.org/html/rfc5789
> 
> > Патч с реализацией TOUCH прилагается, желающие поиграться - добро 
> > пожаловать.  Правда, Игорь считает изобретение новых методов 
> > порочной практикой, так что в коробку этот патч попадёт врядли.
> 
> А если потребуется поменять atime, то:
> -    if (ngx_set_file_time(NULL, fd, ctx->mtime) != NGX_OK) {
> +    if (ngx_set_file_time(NULL, fd, ctx->atime) != NGX_OK) {
> 
> ?
> 
> А  то  я  тут посмотрел код скриптов, работающих с вебдавом, чтоб туда
> идейку  про  перл  в  комменты  записать.  А  там мы оказывается atime
> меняем, а не mtime.

Это cut-n-paste ошибка в виндовой части кода, которую я поленился 
проверить и недоправил.  Там должно быть date, исправленный патч 
прилагается.

> И,  кстати,  Игорь  прав.  ;-)  Глядя  на  твой патч возникает желание
> плодить методы под каждый чих, что неправильно.

С одной стороны да, с другой - иногда надо хотя бы пытаться 
предлагать какую-то альтернативу тому ужасу, что стандартизировал 
Microsoft.  Особенно с учётом того, сколько методов они сами 
наплодили как в стандарте на webdav, так и в дополнение к нему.  
:)


-- 
Maxim Dounin
http://nginx.com/support.html
-------------- next part --------------
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1350409142 -14400
# Node ID d87b65b4be5211a53bf6deadbecd464000779c02
# Parent  eea938da44a1778c4c4f1e2504b774845c86b99f
Dav: experimental TOUCH method support.

The TOUCH method sets the modification and access times of a file.  Note
that in contrast to touch(1) if file doesn't exists, it is not created.

See this thread for details (in Russian):
http://mailman.nginx.org/pipermail/nginx-ru/2012-October/048584.html

diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -55,6 +55,8 @@ static ngx_int_t ngx_http_dav_copy_dir_t
 static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
     ngx_str_t *path);
 
+static ngx_int_t ngx_http_dav_touch_handler(ngx_http_request_t *r);
+
 static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt);
 static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
     ngx_int_t not_found, char *failed, u_char *path);
@@ -72,6 +74,7 @@ static ngx_conf_bitmask_t  ngx_http_dav_
     { ngx_string("mkcol"), NGX_HTTP_MKCOL },
     { ngx_string("copy"), NGX_HTTP_COPY },
     { ngx_string("move"), NGX_HTTP_MOVE },
+    { ngx_string("touch"), NGX_HTTP_TOUCH },
     { ngx_null_string, 0 }
 };
 
@@ -192,6 +195,10 @@ ngx_http_dav_handler(ngx_http_request_t 
     case NGX_HTTP_MOVE:
 
         return ngx_http_dav_copy_move_handler(r);
+
+    case NGX_HTTP_TOUCH:
+
+        return ngx_http_dav_touch_handler(r);
     }
 
     return NGX_DECLINED;
@@ -969,6 +976,76 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx
 
 
 static ngx_int_t
+ngx_http_dav_touch_handler(ngx_http_request_t *r)
+{
+    size_t     root;
+    time_t     date;
+    ngx_int_t  rc;
+    ngx_str_t  path;
+
+    rc = ngx_http_discard_request_body(r);
+
+    if (rc != NGX_OK) {
+        return rc;
+    }
+
+    date = (time_t) NGX_ERROR;
+
+    if (r->headers_in.date) {
+        date = ngx_http_parse_time(r->headers_in.date->value.data,
+                                   r->headers_in.date->value.len);
+    }
+
+    if (date == (time_t) NGX_ERROR) {
+        date = ngx_time();
+    }
+
+    if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http touch filename: \"%s\"", path.data);
+
+#if (NGX_WIN32)
+    {
+    ngx_fd_t  fd;
+    
+    fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
+        
+    if (fd == NGX_INVALID_FILE) {
+        return ngx_http_dav_error(r->connection->log, ngx_errno,
+                                  NGX_HTTP_NOT_FOUND, ngx_open_file_n,
+                                  path.data);
+    }
+     
+    if (ngx_set_file_time(NULL, fd, date) != NGX_OK) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_set_file_time_n " \"%s\" failed", path.data);
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", path.data);
+    }
+    }
+
+#else
+
+    if (ngx_set_file_time(path.data, 0, date) != NGX_OK) {
+        return ngx_http_dav_error(r->connection->log, ngx_errno,
+                                  NGX_HTTP_NOT_FOUND, ngx_set_file_time_n,
+                                  path.data);
+    }
+
+#endif
+
+    return NGX_HTTP_NO_CONTENT;
+}
+
+
+static ngx_int_t
 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt)
 {
     ngx_table_elt_t  *depth;
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -222,6 +222,10 @@ ngx_http_parse_request_line(ngx_http_req
                         r->method = NGX_HTTP_TRACE;
                     }
 
+                    if (ngx_str5cmp(m, 'T', 'O', 'U', 'C', 'H')) {
+                        r->method = NGX_HTTP_TOUCH;
+                    }
+
                     break;
 
                 case 6:
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -24,22 +24,23 @@
 #define NGX_HTTP_VERSION_10                1000
 #define NGX_HTTP_VERSION_11                1001
 
-#define NGX_HTTP_UNKNOWN                   0x0001
-#define NGX_HTTP_GET                       0x0002
-#define NGX_HTTP_HEAD                      0x0004
-#define NGX_HTTP_POST                      0x0008
-#define NGX_HTTP_PUT                       0x0010
-#define NGX_HTTP_DELETE                    0x0020
-#define NGX_HTTP_MKCOL                     0x0040
-#define NGX_HTTP_COPY                      0x0080
-#define NGX_HTTP_MOVE                      0x0100
-#define NGX_HTTP_OPTIONS                   0x0200
-#define NGX_HTTP_PROPFIND                  0x0400
-#define NGX_HTTP_PROPPATCH                 0x0800
-#define NGX_HTTP_LOCK                      0x1000
-#define NGX_HTTP_UNLOCK                    0x2000
-#define NGX_HTTP_PATCH                     0x4000
-#define NGX_HTTP_TRACE                     0x8000
+#define NGX_HTTP_UNKNOWN                   0x000001
+#define NGX_HTTP_GET                       0x000002
+#define NGX_HTTP_HEAD                      0x000004
+#define NGX_HTTP_POST                      0x000008
+#define NGX_HTTP_PUT                       0x000010
+#define NGX_HTTP_DELETE                    0x000020
+#define NGX_HTTP_MKCOL                     0x000040
+#define NGX_HTTP_COPY                      0x000080
+#define NGX_HTTP_MOVE                      0x000100
+#define NGX_HTTP_OPTIONS                   0x000200
+#define NGX_HTTP_PROPFIND                  0x000400
+#define NGX_HTTP_PROPPATCH                 0x000800
+#define NGX_HTTP_LOCK                      0x001000
+#define NGX_HTTP_UNLOCK                    0x002000
+#define NGX_HTTP_PATCH                     0x004000
+#define NGX_HTTP_TRACE                     0x008000
+#define NGX_HTTP_TOUCH                     0x010000
 
 #define NGX_HTTP_CONNECTION_CLOSE          1
 #define NGX_HTTP_CONNECTION_KEEP_ALIVE     2


Подробная информация о списке рассылки nginx-ru