XS-libuv
view release on metacpan or search on metacpan
libuv-1.49.2/src/unix/fs.c view on Meta::CPAN
destination are not the same file. If they are the same, bail out early. */
if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) {
/* Get the destination file's mode. */
if (uv__fstat(dstfd, &dst_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
/* Check if srcfd and dstfd refer to the same file */
if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
src_statsbuf.st_ino == dst_statsbuf.st_ino) {
goto out;
}
/* Truncate the file in case the destination already existed. */
if (ftruncate(dstfd, 0) != 0) {
err = UV__ERR(errno);
/* ftruncate() on ceph-fuse fails with EACCES when the file is created
* with read only permissions. Since ftruncate() on a newly created
* file is a meaningless operation anyway, detect that condition
* and squelch the error.
*/
if (err != UV_EACCES)
goto out;
if (dst_statsbuf.st_size > 0)
goto out;
err = 0;
}
}
/**
* Change the timestamps of the destination file to match the source file.
*/
#if defined(__APPLE__)
times[0] = src_statsbuf.st_atimespec;
times[1] = src_statsbuf.st_mtimespec;
#elif defined(_AIX)
times[0].tv_sec = src_statsbuf.st_atime;
times[0].tv_nsec = src_statsbuf.st_atime_n;
times[1].tv_sec = src_statsbuf.st_mtime;
times[1].tv_nsec = src_statsbuf.st_mtime_n;
#else
times[0] = src_statsbuf.st_atim;
times[1] = src_statsbuf.st_mtim;
#endif
if (futimens(dstfd, times) == -1) {
err = UV__ERR(errno);
goto out;
}
/*
* Change the ownership and permissions of the destination file to match the
* source file.
* `cp -p` does not care about errors here, so we don't either. Reuse the
* `result` variable to silence a -Wunused-result warning.
*/
result = fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid);
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
err = UV__ERR(errno);
#ifdef __linux__
/* fchmod() on CIFS shares always fails with EPERM unless the share is
* mounted with "noperm". As fchmod() is a meaningless operation on such
* shares anyway, detect that condition and squelch the error.
*/
if (err != UV_EPERM)
goto out;
if (!uv__is_cifs_or_smb(dstfd))
goto out;
err = 0;
#else /* !__linux__ */
goto out;
#endif /* !__linux__ */
}
#ifdef FICLONE
if (req->flags & UV_FS_COPYFILE_FICLONE ||
req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
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;
}
}
#else
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
err = UV_ENOSYS;
goto out;
}
#endif
bytes_to_send = src_statsbuf.st_size;
in_offset = 0;
while (bytes_to_send != 0) {
bytes_chunk = SSIZE_MAX;
if (bytes_to_send < (off_t) bytes_chunk)
bytes_chunk = bytes_to_send;
uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_chunk, NULL);
bytes_written = fs_req.result;
uv_fs_req_cleanup(&fs_req);
if (bytes_written < 0) {
err = bytes_written;
break;
}
bytes_to_send -= bytes_written;
in_offset += bytes_written;
}
libuv-1.49.2/src/unix/fs.c view on Meta::CPAN
iovmax = uv__getiovmax();
nbufs = req->nbufs;
bufs = req->bufs;
total = 0;
while (nbufs > 0) {
req->nbufs = nbufs;
if (req->nbufs > iovmax)
req->nbufs = iovmax;
do
result = uv__fs_write(req);
while (result < 0 && errno == EINTR);
if (result <= 0) {
if (total == 0)
total = result;
break;
}
if (req->off >= 0)
req->off += result;
req->nbufs = uv__fs_buf_offset(req->bufs, result);
req->bufs += req->nbufs;
nbufs -= req->nbufs;
total += result;
}
if (bufs != req->bufsml)
uv__free(bufs);
req->bufs = NULL;
req->nbufs = 0;
return total;
}
static void uv__fs_work(struct uv__work* w) {
int retry_on_eintr;
uv_fs_t* req;
ssize_t r;
req = container_of(w, uv_fs_t, work_req);
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
req->fs_type == UV_FS_READ);
do {
errno = 0;
#define X(type, action) \
case UV_FS_ ## type: \
r = action; \
break;
switch (req->fs_type) {
X(ACCESS, access(req->path, req->flags));
X(CHMOD, chmod(req->path, req->mode));
X(CHOWN, chown(req->path, req->uid, req->gid));
X(CLOSE, uv__fs_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(LCHOWN, lchown(req->path, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
X(FSYNC, uv__fs_fsync(req));
X(FTRUNCATE, ftruncate(req->file, req->off));
X(FUTIME, uv__fs_futime(req));
X(LUTIME, uv__fs_lutime(req));
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
X(LINK, link(req->path, req->new_path));
X(MKDIR, mkdir(req->path, req->mode));
X(MKDTEMP, uv__fs_mkdtemp(req));
X(MKSTEMP, uv__fs_mkstemp(req));
X(OPEN, uv__fs_open(req));
X(READ, uv__fs_read(req));
X(SCANDIR, uv__fs_scandir(req));
X(OPENDIR, uv__fs_opendir(req));
X(READDIR, uv__fs_readdir(req));
X(CLOSEDIR, uv__fs_closedir(req));
X(READLINK, uv__fs_readlink(req));
X(REALPATH, uv__fs_realpath(req));
X(RENAME, rename(req->path, req->new_path));
X(RMDIR, rmdir(req->path));
X(SENDFILE, uv__fs_sendfile(req));
X(STAT, uv__fs_stat(req->path, &req->statbuf));
X(STATFS, uv__fs_statfs(req));
X(SYMLINK, symlink(req->path, req->new_path));
X(UNLINK, unlink(req->path));
X(UTIME, uv__fs_utime(req));
X(WRITE, uv__fs_write_all(req));
default: abort();
}
#undef X
} while (r == -1 && errno == EINTR && retry_on_eintr);
if (r == -1)
req->result = UV__ERR(errno);
else
req->result = r;
if (r == 0 && (req->fs_type == UV_FS_STAT ||
req->fs_type == UV_FS_FSTAT ||
req->fs_type == UV_FS_LSTAT)) {
req->ptr = &req->statbuf;
}
}
static void uv__fs_done(struct uv__work* w, int status) {
uv_fs_t* req;
req = container_of(w, uv_fs_t, work_req);
uv__req_unregister(req->loop);
if (status == UV_ECANCELED) {
assert(req->result == 0);
req->result = UV_ECANCELED;
}
req->cb(req);
}
void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) {
uv__req_register(loop);
uv__work_submit(loop,
&req->work_req,
UV__WORK_FAST_IO,
uv__fs_work,
uv__fs_done);
}
int uv_fs_access(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
int flags,
uv_fs_cb cb) {
INIT(ACCESS);
PATH;
req->flags = flags;
POST;
}
int uv_fs_chmod(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
int mode,
uv_fs_cb cb) {
INIT(CHMOD);
PATH;
req->mode = mode;
POST;
}
int uv_fs_chown(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
uv_uid_t uid,
uv_gid_t gid,
uv_fs_cb cb) {
INIT(CHOWN);
PATH;
req->uid = uid;
req->gid = gid;
POST;
}
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(CLOSE);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_close(loop, req))
return 0;
POST;
}
int uv_fs_fchmod(uv_loop_t* loop,
uv_fs_t* req,
uv_file file,
int mode,
uv_fs_cb cb) {
INIT(FCHMOD);
req->file = file;
req->mode = mode;
POST;
}
int uv_fs_fchown(uv_loop_t* loop,
uv_fs_t* req,
uv_file file,
uv_uid_t uid,
uv_gid_t gid,
uv_fs_cb cb) {
INIT(FCHOWN);
req->file = file;
req->uid = uid;
req->gid = gid;
POST;
}
int uv_fs_lchown(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
uv_uid_t uid,
uv_gid_t gid,
uv_fs_cb cb) {
INIT(LCHOWN);
PATH;
req->uid = uid;
req->gid = gid;
POST;
}
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(FDATASYNC);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_fsync_or_fdatasync(loop, req, /* IORING_FSYNC_DATASYNC */ 1))
return 0;
POST;
}
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(FSTAT);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_statx(loop, req, /* is_fstat */ 1, /* is_lstat */ 0))
return 0;
POST;
}
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
INIT(FSYNC);
req->file = file;
if (cb != NULL)
if (uv__iou_fs_fsync_or_fdatasync(loop, req, /* no flags */ 0))
return 0;
POST;
}
int uv_fs_ftruncate(uv_loop_t* loop,
uv_fs_t* req,
uv_file file,
int64_t off,
uv_fs_cb cb) {
INIT(FTRUNCATE);
req->file = file;
req->off = off;
if (cb != NULL)
if (uv__iou_fs_ftruncate(loop, req))
return 0;
POST;
}
int uv_fs_futime(uv_loop_t* loop,
uv_fs_t* req,
( run in 0.573 second using v1.01-cache-2.11-cpan-5511b514fd6 )