Пример #1
0
/* copy a file from one to another. */
void MVM_file_copy(MVMThreadContext *tc, MVMString *src, MVMString *dest) {
    uv_fs_t req;
    char *       const a = MVM_string_utf8_encode_C_string(tc, src);
    const uv_file  in_fd = uv_fs_open(tc->loop, &req, (const char *)a, O_RDONLY, 0, NULL);

    if (in_fd >= 0 && uv_fs_stat(tc->loop, &req, a, NULL) >= 0) {
        char *       const b = MVM_string_utf8_encode_C_string(tc, dest);
        const uv_file out_fd = uv_fs_open(tc->loop, &req, (const char *)b, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_MODE, NULL);
        MVM_free(a);

        if (out_fd >= 0
                && uv_fs_sendfile(tc->loop, &req, out_fd, in_fd, 0, req.statbuf.st_size, NULL) >= 0) {
            MVM_free(b);

            if (uv_fs_close(tc->loop, &req, in_fd, NULL) < 0) {
                uv_fs_close(tc->loop, &req, out_fd, NULL); /* should close out_fd before throw. */
                MVM_exception_throw_adhoc(tc, "Failed to close file: %s", uv_strerror(req.result));
            }

            if (uv_fs_close(tc->loop, &req, out_fd, NULL) < 0) {
                MVM_exception_throw_adhoc(tc, "Failed to close file: %s", uv_strerror(req.result));
            }

            return;
        }
        else
            MVM_free(b);
    }
    else
        MVM_free(a);

    MVM_exception_throw_adhoc(tc, "Failed to copy file: %s", uv_strerror(req.result));
}
Пример #2
0
Файл: jl_uv.c Проект: 0/julia
JL_DLLEXPORT int jl_fs_sendfile(int src_fd, int dst_fd,
                                int64_t in_offset, size_t len)
{
    uv_fs_t req;
    JL_SIGATOMIC_BEGIN();
    int ret = uv_fs_sendfile(jl_io_loop, &req, dst_fd, src_fd,
                             in_offset, len, NULL);
    uv_fs_req_cleanup(&req);
    JL_SIGATOMIC_END();
    return ret;
}
Пример #3
0
Файл: fs.c Проект: Mikhaska/node
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
}
Пример #4
0
/* 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. */
    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;
    }

    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);
    }
}
Пример #5
0
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;

#ifdef COPYFILE_CLONE
  if (req->flags & UV_FS_COPYFILE_FICLONE)
    flags |= COPYFILE_CLONE;
#endif

  if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
#ifdef COPYFILE_CLONE_FORCE
    flags |= COPYFILE_CLONE_FORCE;
#else
    return UV_ENOSYS;
#endif
  }

  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 = UV__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 = UV__ERR(errno);
    goto out;
  }

#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 {
      goto out;
    }
  }
#else
  if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
    err = UV_ENOSYS;
    goto out;
  }
#endif

  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);
    }
  }

  if (result == 0)
    return 0;

  errno = UV__ERR(result);
  return -1;
#endif
}