Opened 7 years ago
Closed 7 years ago
#1577 closed defect (fixed)
When the file is moved to the directory that the disk is different by the MOVE method under the following conditions, content of moved file is not correct.
| Reported by: | Owned by: | ||
|---|---|---|---|
| Priority: | minor | Milestone: | |
| Component: | other | Version: | 1.12.x |
| Keywords: | WebDAV | Cc: | |
| uname -a: | Linux vm-search-004.fcxlocal 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux | ||
| nginx -V: |
nginx version: nginx/1.12.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' |
||
Description
When the file is moved to the directory that the disk is different by the MOVE method under the following conditions, content of moved file is not correct.
- OS: CentOS 7.4
- Nginx Version: 1.12.2
# df -h Filesystem Size Used Avail Use% Mounted on /dev/vda1 30G 1.4G 29G 5% / devtmpfs 899M 0 899M 0% /dev tmpfs 920M 0 920M 0% /dev/shm tmpfs 920M 17M 904M 2% /run tmpfs 920M 0 920M 0% /sys/fs/cgroup /dev/vdb1 50G 33M 50G 1% /ext_disk tmpfs 184M 0 184M 0% /run/user/1000 # nginx # ps auxf | grep nginx root 18826 0.0 0.0 112660 972 pts/1 S+ 02:45 0:00 | \_ grep --color=auto nginx root 18797 0.0 0.0 46432 988 ? Ss 02:17 0:00 nginx: master process nginx nginx 18798 0.0 0.1 46840 2212 ? S 02:17 0:00 \_ nginx: worker process # cd /var/lib/nginx # ls -l total 0 lrwxrwxrwx. 1 root root 14 May 15 07:50 dest -> /ext_disk/dest drwxr-xr-x. 2 nginx nginx 22 May 16 02:29 source drwxr-xr-x. 2 nginx nginx 6 May 15 07:35 tmp # ls -l source/. total 4 -rw-r--r--. 1 nginx nginx 5 May 16 02:29 move.txt # cat source/move.txt move # ls -l dest/. total 0 # curl -XMOVE http://localhost:8080/source/move.txt -H Destination:/dest/move.txt # ls -l source/. total 0 # ls -l dest/. total 4 ----------. 1 nginx nginx 5 May 16 02:33 move.txt # cat dest/move.txt move
I have attached the configuration file, the access log, and the error log at the debug level.
I expected that the permissions of "dest/move.txt" and "source/move.txt" were equal after MOVE had been done.
However, the permission of "dest/move.txt" is 000("----------").
What should I do to get the expected result?
Attachments (3)
Change History (6)
by , 7 years ago
| Attachment: | access.log added |
|---|
by , 7 years ago
by , 7 years ago
| Attachment: | my-nginx.conf added |
|---|
comment:1 by , 7 years ago
comment:3 by , 7 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
Fix committed, thanks for reporting this.
Note:
See TracTickets
for help on using tickets.

The following patch series should fix this:
# HG changeset patch # User Maxim Dounin <mdounin@mdounin.ru> # Date 1531147912 -10800 # Mon Jul 09 17:51:52 2018 +0300 # Node ID a1668faa205aa6ee0ce7936bdbb15e4e600b3931 # Parent 54683f650cbdcd73f7f8d845c843295978da5a85 Fixed ngx_copy_file() to truncate destination file. Previously, ngx_open_file(NGX_FILE_CREATE_OR_OPEN) was used, resulting in destination file being partially rewritten if exists. Notably, this affected WebDAV COPY command (ticket #1576). diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -839,8 +839,7 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - cf->access); + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, cf->access); if (nfd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, # HG changeset patch # User Maxim Dounin <mdounin@mdounin.ru> # Date 1531156413 -10800 # Mon Jul 09 20:13:33 2018 +0300 # Node ID cb76bc603dadf79bc475e4b6f2139030aff0fab9 # Parent a1668faa205aa6ee0ce7936bdbb15e4e600b3931 Changed ngx_copy_file() to preserve access and mtime. This fixes wrong permissions and file time after cross-device MOVE in the DAV module (ticket #1577). Broken in dbe746851b31 (0.7.27) when switching to ngx_ext_rename_file(). With this change, ngx_copy_file() always calls ngx_set_file_time(), either with the time provided, or with the time from the original file. This is considered acceptable given that copying the file is costly anyway, and optimizing cases when we do not need to preserve time will require interface changes. diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -796,10 +796,12 @@ ngx_copy_file(u_char *from, u_char *to, { char *buf; off_t size; + time_t time; size_t len; ssize_t n; ngx_fd_t fd, nfd; ngx_int_t rc; + ngx_uint_t access; ngx_file_info_t fi; rc = NGX_ERROR; @@ -814,8 +816,10 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - if (cf->size != -1) { + if (cf->size != -1 && cf->access != 0 && cf->time != -1) { size = cf->size; + access = cf->access; + time = cf->time; } else { if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { @@ -825,7 +829,9 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - size = ngx_file_size(&fi); + size = (cf->size != -1) ? cf->size : ngx_file_size(&fi); + access = cf->access ? cf->access : ngx_file_access(&fi); + time = (cf->time != -1) ? cf->time : ngx_file_mtime(&fi); } len = cf->buf_size ? cf->buf_size : 65536; @@ -839,7 +845,7 @@ ngx_copy_file(u_char *from, u_char *to, goto failed; } - nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, cf->access); + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, access); if (nfd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, @@ -886,12 +892,10 @@ ngx_copy_file(u_char *from, u_char *to, size -= n; } - if (cf->time != -1) { - if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", to); - goto failed; - } + if (ngx_set_file_time(to, nfd, time) != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; } rc = NGX_OK;