Skip to content

Commit

Permalink
Merge pull request #808 from ugexe/uv_fs_copyfile
Browse files Browse the repository at this point in the history
Use uv_fs_copyfile api
  • Loading branch information
niner committed Feb 22, 2018
2 parents 1849ae6 + 4ff0bad commit 4226137
Showing 1 changed file with 7 additions and 67 deletions.
74 changes: 7 additions & 67 deletions src/io/fileops.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,80 +120,20 @@ MVMnum64 MVM_file_time(MVMThreadContext *tc, MVMString *filename, MVMint64 statu

/* copy a file from one to another */
void MVM_file_copy(MVMThreadContext *tc, MVMString *src, MVMString * dest) {
/* TODO: on Windows we can use the CopyFile API, which is probaly
more efficient, not to mention easier to use. */
char * const a = MVM_string_utf8_c8_encode_C_string(tc, src);
char * const b = MVM_string_utf8_c8_encode_C_string(tc, dest);
uv_fs_t req;
char * a, * b;
uv_file in_fd = -1, out_fd = -1;
MVMuint64 size, offset;

a = MVM_string_utf8_c8_encode_C_string(tc, src);
b = MVM_string_utf8_c8_encode_C_string(tc, dest);

/* If the file cannot be stat(), there is little point in going any further. */
if (uv_fs_stat(tc->loop, &req, a, NULL) < 0)
goto failure;
size = req.statbuf.st_size;

in_fd = uv_fs_open(tc->loop, &req, (const char *)a, O_RDONLY, 0, NULL);
if (in_fd < 0) {
goto failure;
}

out_fd = uv_fs_open(tc->loop, &req, (const char *)b, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_MODE, NULL);
if (out_fd < 0) {
goto failure;
}

offset = 0;
do {
/* sendfile() traditionally takes offset as a pointer argument
* used a both input and output. libuv deviates by making
* offset an integer and returning the number of bytes
* sent. So it is necessary to add these explicitly. */
MVMint64 sent = uv_fs_sendfile(tc->loop, &req, out_fd, in_fd, offset, size - offset, NULL);
if (sent < 0) {
goto failure;
}
offset += sent;
} while (offset < size);

/* Cleanup */
if(uv_fs_close(tc->loop, &req, in_fd, NULL) < 0) {
goto failure;
}
in_fd = -1;

if (uv_fs_close(tc->loop, &req, out_fd, NULL) < 0) {
goto failure;
if(uv_fs_copyfile(tc->loop, &req, a, b, 0, NULL) < 0) {
MVM_free(a);
MVM_free(b);
MVM_exception_throw_adhoc(tc, "Failed to copy file: %s", uv_strerror(req.result));
}

MVM_free(b);
MVM_free(a);
return;

failure: {
/* First get the error, since it may be overwritten further on. */
const char * error = uv_strerror(req.result);
/* Basic premise: dealing with all failure cases is hard.
* So to simplify, a and b are allocated in all conditions.
* Also to simplify, in_fd are nonnegative if open, negative
* otherwise. */
MVM_free(b);
MVM_free(a);
/* If any of these fail there is nothing
* further to do, since we're already failing */
if (in_fd >= 0)
uv_fs_close(tc->loop, &req, in_fd, NULL);
if (out_fd >= 0)
uv_fs_close(tc->loop, &req, out_fd, NULL);
/* This function only throws adhoc errors, so the message is for
* progammer eyes only */
MVM_exception_throw_adhoc(tc, "Failed to copy file: %s", error);
}
MVM_free(b);
}


/* rename one file to another. */
void MVM_file_rename(MVMThreadContext *tc, MVMString *src, MVMString *dest) {
char * const a = MVM_string_utf8_c8_encode_C_string(tc, src);
Expand Down

0 comments on commit 4226137

Please sign in to comment.