diff options
author | Stefan Bender <stefan.bender@ntnu.no> | 2019-10-14 17:02:58 +0200 |
---|---|---|
committer | cjihrig <cjihrig@gmail.com> | 2019-10-16 10:49:42 -0400 |
commit | ddcaff9a10a84ed34353dbafd65e3c0693dd0b35 (patch) | |
tree | d816674100d5fdc7f10089a5a1ff22e339e52181 /src/unix/fs.c | |
parent | f9c35197e64202099b691d53df7ea7db480b390c (diff) | |
download | libuv-ddcaff9a10a84ed34353dbafd65e3c0693dd0b35.tar.gz libuv-ddcaff9a10a84ed34353dbafd65e3c0693dd0b35.zip |
unix: update uv_fs_copyfile() fallback logic
This commit fixes uv_fs_copyfile() in cases where an unknown error
occurs when copy-on-write is requested by setting
UV_FS_COPYFILE_FICLONE. The original approach tried to catch some of
the errors raised by the ioctl() call, assuming that sendfile() would
also fail in those cases. This is not necessarily true, as some
variants of ioctl() also raise EINVAL (some maybe EBADF), but sendfile()
works just fine.
This patch reverses the logic, falling back to sendfile() in any
case where ioctl() returns an error. In other words, it tries much
harder to make uv_fs_copyfile() work.
Related to that, the original approach returned UV_ENOTSUP
unconditionally in cases where ioctl() failed and
UV_FS_COPYFILE_FICLONE_FORCE was set. However, ioctl() may have
failed for other reasons than being not supported. The function
now returns the actual error raised by ioctl(), leaving it to the
caller to deal with it.
Fixes: https://github.com/libuv/libuv/issues/2483
PR-URL: https://github.com/libuv/libuv/pull/2514
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'src/unix/fs.c')
-rw-r--r-- | src/unix/fs.c | 20 |
1 files changed, 8 insertions, 12 deletions
diff --git a/src/unix/fs.c b/src/unix/fs.c index f812b24e..b37cfbbc 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1055,18 +1055,14 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { #ifdef FICLONE if (req->flags & UV_FS_COPYFILE_FICLONE || req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { - if (ioctl(dstfd, FICLONE, srcfd) == -1) { - /* If an error occurred that the sendfile fallback also won't handle, or - this is a force clone then exit. Otherwise, fall through to try using - sendfile(). */ - if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) { - err = UV__ERR(errno); - goto out; - } else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { - err = UV_ENOTSUP; - goto out; - } - } else { + if (ioctl(dstfd, FICLONE, srcfd) == 0) { + /* ioctl() with FICLONE succeeded. */ + goto out; + } + /* If an error occurred and force was set, return the error to the caller; + * fall back to sendfile() when force was not set. */ + if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + err = UV__ERR(errno); goto out; } } |