[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