summaryrefslogtreecommitdiffstats
path: root/Utilities/cmlibuv/src/unix/fs.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2018-01-19 18:03:04 (GMT)
committerBrad King <brad.king@kitware.com>2018-01-19 18:03:04 (GMT)
commitb58d48c15f9ee18015960e2eed7410f5166c855f (patch)
tree640add606d5ca6c0a03f58589a7528eaa9511428 /Utilities/cmlibuv/src/unix/fs.c
parente8b57c2283f731f42b4c7eece0531dab67df3d41 (diff)
parentf4a26c748b5ea2cafecdf5490b744a2b167c01ae (diff)
downloadCMake-b58d48c15f9ee18015960e2eed7410f5166c855f.zip
CMake-b58d48c15f9ee18015960e2eed7410f5166c855f.tar.gz
CMake-b58d48c15f9ee18015960e2eed7410f5166c855f.tar.bz2
Merge branch 'upstream-libuv' into update-libuv
* upstream-libuv: libuv 2018-01-19 (63de1eca)
Diffstat (limited to 'Utilities/cmlibuv/src/unix/fs.c')
-rw-r--r--Utilities/cmlibuv/src/unix/fs.c177
1 files changed, 165 insertions, 12 deletions
diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c
index 82c91ef..0a4c183 100644
--- a/Utilities/cmlibuv/src/unix/fs.c
+++ b/Utilities/cmlibuv/src/unix/fs.c
@@ -60,8 +60,14 @@
# include <sys/sendfile.h>
#endif
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
#define INIT(subtype) \
do { \
+ if (req == NULL) \
+ return -EINVAL; \
req->type = UV_FS; \
if (cb != NULL) \
uv__req_init(loop, req, UV_FS); \
@@ -126,26 +132,33 @@
while (0)
-static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
-#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
- return fdatasync(req->file);
-#elif defined(__APPLE__)
+static ssize_t uv__fs_fsync(uv_fs_t* req) {
+#if defined(__APPLE__)
/* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
* to the drive platters. This is in contrast to Linux's fdatasync and fsync
* which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
- * for flushing buffered data to permanent storage.
+ * for flushing buffered data to permanent storage. If F_FULLFSYNC is not
+ * supported by the file system we should fall back to fsync(). This is the
+ * same approach taken by sqlite.
*/
- return fcntl(req->file, F_FULLFSYNC);
+ int r;
+
+ r = fcntl(req->file, F_FULLFSYNC);
+ if (r != 0 && errno == ENOTTY)
+ r = fsync(req->file);
+ return r;
#else
return fsync(req->file);
#endif
}
-static ssize_t uv__fs_fsync(uv_fs_t* req) {
-#if defined(__APPLE__)
- /* See the comment in uv__fs_fdatasync. */
- return fcntl(req->file, F_FULLFSYNC);
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+ return fdatasync(req->file);
+#elif defined(__APPLE__)
+ /* See the comment in uv__fs_fsync. */
+ return uv__fs_fsync(req);
#else
return fsync(req->file);
#endif
@@ -442,7 +455,12 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
return -1;
}
+#if defined(__MVS__)
+ len = os390_readlink(req->path, buf, len);
+#else
len = readlink(req->path, buf, len);
+#endif
+
if (len == -1) {
uv__free(buf);
@@ -776,6 +794,118 @@ done:
return r;
}
+static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+ /* On macOS, use the native copyfile(3). */
+ copyfile_flags_t flags;
+
+ flags = COPYFILE_ALL;
+
+ if (req->flags & UV_FS_COPYFILE_EXCL)
+ flags |= COPYFILE_EXCL;
+
+ return copyfile(req->path, req->new_path, NULL, flags);
+#else
+ uv_fs_t fs_req;
+ uv_file srcfd;
+ uv_file dstfd;
+ struct stat statsbuf;
+ int dst_flags;
+ int result;
+ int err;
+ size_t bytes_to_send;
+ int64_t in_offset;
+
+ dstfd = -1;
+ err = 0;
+
+ /* Open the source file. */
+ srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL);
+ uv_fs_req_cleanup(&fs_req);
+
+ if (srcfd < 0)
+ return srcfd;
+
+ /* Get the source file's mode. */
+ if (fstat(srcfd, &statsbuf)) {
+ err = -errno;
+ goto out;
+ }
+
+ dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+ if (req->flags & UV_FS_COPYFILE_EXCL)
+ dst_flags |= O_EXCL;
+
+ /* Open the destination file. */
+ dstfd = uv_fs_open(NULL,
+ &fs_req,
+ req->new_path,
+ dst_flags,
+ statsbuf.st_mode,
+ NULL);
+ uv_fs_req_cleanup(&fs_req);
+
+ if (dstfd < 0) {
+ err = dstfd;
+ goto out;
+ }
+
+ if (fchmod(dstfd, statsbuf.st_mode) == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ bytes_to_send = statsbuf.st_size;
+ in_offset = 0;
+ while (bytes_to_send != 0) {
+ err = uv_fs_sendfile(NULL,
+ &fs_req,
+ dstfd,
+ srcfd,
+ in_offset,
+ bytes_to_send,
+ NULL);
+ uv_fs_req_cleanup(&fs_req);
+ if (err < 0)
+ break;
+ bytes_to_send -= fs_req.result;
+ in_offset += fs_req.result;
+ }
+
+out:
+ if (err < 0)
+ result = err;
+ else
+ result = 0;
+
+ /* Close the source file. */
+ err = uv__close_nocheckstdio(srcfd);
+
+ /* Don't overwrite any existing errors. */
+ if (err != 0 && result == 0)
+ result = err;
+
+ /* Close the destination file if it is open. */
+ if (dstfd >= 0) {
+ err = uv__close_nocheckstdio(dstfd);
+
+ /* Don't overwrite any existing errors. */
+ if (err != 0 && result == 0)
+ result = err;
+
+ /* Remove the destination file if something went wrong. */
+ if (result != 0) {
+ uv_fs_unlink(NULL, &fs_req, req->new_path, NULL);
+ /* Ignore the unlink return value, as an error already happened. */
+ uv_fs_req_cleanup(&fs_req);
+ }
+ }
+
+ return result;
+#endif
+}
+
static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_dev = src->st_dev;
dst->st_mode = src->st_mode;
@@ -956,6 +1086,7 @@ static void uv__fs_work(struct uv__work* w) {
X(CHMOD, chmod(req->path, req->mode));
X(CHOWN, chown(req->path, req->uid, req->gid));
X(CLOSE, close(req->file));
+ X(COPYFILE, uv__fs_copyfile(req));
X(FCHMOD, fchmod(req->file, req->mode));
X(FCHOWN, fchown(req->file, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
@@ -1196,10 +1327,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
+ INIT(READ);
+
if (bufs == NULL || nbufs == 0)
return -EINVAL;
- INIT(READ);
req->file = file;
req->nbufs = nbufs;
@@ -1334,10 +1466,11 @@ int uv_fs_write(uv_loop_t* loop,
unsigned int nbufs,
int64_t off,
uv_fs_cb cb) {
+ INIT(WRITE);
+
if (bufs == NULL || nbufs == 0)
return -EINVAL;
- INIT(WRITE);
req->file = file;
req->nbufs = nbufs;
@@ -1359,6 +1492,9 @@ int uv_fs_write(uv_loop_t* loop,
void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req == NULL)
+ return;
+
/* Only necessary for asychronous requests, i.e., requests with a callback.
* Synchronous ones don't copy their arguments and have req->path and
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
@@ -1377,3 +1513,20 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
uv__free(req->ptr);
req->ptr = NULL;
}
+
+
+int uv_fs_copyfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(COPYFILE);
+
+ if (flags & ~UV_FS_COPYFILE_EXCL)
+ return -EINVAL;
+
+ PATH2;
+ req->flags = flags;
+ POST;
+}