int guestfs_impl_copy_in (guestfs_h *g, const char *localpath, const char *remotedir) { CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); int fd; int r; char fdbuf[64]; size_t buf_len = strlen (localpath) + 1; char buf[buf_len]; const char *dirname, *basename; int remote_is_dir = guestfs_is_dir (g, remotedir); if (remote_is_dir == -1) return -1; if (!remote_is_dir) { error (g, _("target '%s' is not a directory"), remotedir); return -1; } if (split_path (g, buf, buf_len, localpath, &dirname, &basename) == -1) return -1; guestfs_int_cmd_add_arg (cmd, "tar"); if (dirname) { guestfs_int_cmd_add_arg (cmd, "-C"); guestfs_int_cmd_add_arg (cmd, dirname); } guestfs_int_cmd_add_arg (cmd, "-cf"); guestfs_int_cmd_add_arg (cmd, "-"); guestfs_int_cmd_add_arg (cmd, basename); r = guestfs_int_cmd_run_async (cmd, NULL, NULL, &fd, NULL); if (r == -1) return -1; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd); r = guestfs_tar_in (g, fdbuf, remotedir); if (close (fd) == -1) { perrorf (g, "close (tar subprocess)"); return -1; } r = guestfs_int_cmd_wait (cmd); if (r == -1) return -1; if (!(WIFEXITED (r) && WEXITSTATUS (r) == 0)) return -1; return 0; }
int run_copy_in (const char *cmd, size_t argc, char *argv[]) { if (argc < 2) { fprintf (stderr, _("use 'copy-in <local> [<local>...] <remotedir>' to copy files into the image\n")); return -1; } /* Remote directory is always the last arg. */ char *remote = argv[argc-1]; /* Allow win: prefix on remote. */ remote = win_prefix (remote); if (remote == NULL) return -1; int nr_locals = argc-1; int remote_is_dir = guestfs_is_dir (g, remote); if (remote_is_dir == -1) { free (remote); return -1; } if (!remote_is_dir) { fprintf (stderr, _("copy-in: target '%s' is not a directory\n"), remote); free (remote); return -1; } /* Upload each local one at a time using tar-in. */ int i; for (i = 0; i < nr_locals; ++i) { struct fd_pid fdpid = make_tar_from_local (argv[i]); if (fdpid.fd == -1) { free (remote); return -1; } char fdbuf[64]; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fdpid.fd); int r = guestfs_tar_in (g, fdbuf, remote); if (close (fdpid.fd) == -1) { perror ("close (tar-from-local subprocess)"); r = -1; } int status; if (waitpid (fdpid.pid, &status, 0) == -1) { perror ("wait (tar-from-local subprocess)"); free (remote); return -1; } if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0)) { free (remote); return -1; } if (r == -1) { free (remote); return -1; } } free (remote); return 0; }
int guestfs_impl_copy_in (guestfs_h *g, const char *localpath, const char *remotedir) { CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g); int fd; int r; char fdbuf[64]; size_t buf_len = strlen (localpath) + 1; CLEANUP_FREE char *buf = safe_malloc (g, buf_len); const char *dirname, *basename; struct stat statbuf; if (stat (localpath, &statbuf) == -1) { error (g, _("source '%s' does not exist (or cannot be read)"), localpath); return -1; } int remote_is_dir = guestfs_is_dir (g, remotedir); if (remote_is_dir == -1) return -1; if (!remote_is_dir) { error (g, _("target '%s' is not a directory"), remotedir); return -1; } if (split_path (g, buf, buf_len, localpath, &dirname, &basename) == -1) return -1; guestfs_int_cmd_add_arg (cmd, "tar"); if (dirname) { guestfs_int_cmd_add_arg (cmd, "-C"); guestfs_int_cmd_add_arg (cmd, dirname); } guestfs_int_cmd_add_arg (cmd, "-cf"); guestfs_int_cmd_add_arg (cmd, "-"); guestfs_int_cmd_add_arg (cmd, basename); guestfs_int_cmd_clear_capture_errors (cmd); fd = guestfs_int_cmd_pipe_run (cmd, "r"); if (fd == -1) return -1; snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd); r = guestfs_tar_in (g, fdbuf, remotedir); if (close (fd) == -1) { perrorf (g, "close (tar subprocess)"); return -1; } r = guestfs_int_cmd_pipe_wait (cmd); if (r == -1) return -1; if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { CLEANUP_FREE char *errors = guestfs_int_cmd_get_pipe_errors (cmd); if (errors == NULL) return -1; error (g, "tar subprocess failed: %s", errors); return -1; } return 0; }
int main (int argc, char *argv[]) { const char *src, *srcdir, *dest, *destdir; guestfs_h *destg; int fd[2]; pthread_t srcthread; struct threaddata threaddata; int err; char fdname[128]; struct timeval start_t, end_t; int64_t ms; if (argc != 5) { usage (); exit (EXIT_FAILURE); } src = argv[1]; srcdir = argv[2]; dest = argv[3]; destdir = argv[4]; /* Instead of downloading to local disk and uploading, we are going * to connect the source download and destination upload using a * pipe. Create that pipe. */ if (pipe (fd) == -1) { perror ("pipe"); exit (EXIT_FAILURE); } /* We don't want the pipe to be passed to subprocesses. */ if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) == -1 || fcntl (fd[1], F_SETFD, FD_CLOEXEC) == -1) { perror ("fcntl"); exit (EXIT_FAILURE); } /* The libguestfs API is synchronous, so if we want to use two * handles concurrently, then we have to have two threads. In this * case the main thread (this one) is handling the destination * domain (uploading), and we create one more thread to handle the * source domain (downloading). */ threaddata.src = src; threaddata.srcdir = srcdir; threaddata.fd = fd[1]; threaddata.mainthread = pthread_self (); err = pthread_create (&srcthread, NULL, start_srcthread, &threaddata); if (err != 0) { fprintf (stderr, "pthread_create: %s\n", strerror (err)); exit (EXIT_FAILURE); } /* Open the destination domain. */ destg = guestfs_create (); if (!destg) { perror ("failed to create libguestfs handle"); pthread_cancel (srcthread); exit (EXIT_FAILURE); } if (open_guest (destg, dest, 0) == -1) { pthread_cancel (srcthread); exit (EXIT_FAILURE); } gettimeofday (&start_t, NULL); /* Begin the upload. */ snprintf (fdname, sizeof fdname, "/dev/fd/%d", fd[0]); if (guestfs_tar_in (destg, fdname, destdir) == -1) { pthread_cancel (srcthread); exit (EXIT_FAILURE); } /* Close our end of the pipe. The other thread will close the * other side of the pipe. */ close (fd[0]); /* Wait for the other thread to finish. */ err = pthread_join (srcthread, NULL); if (err != 0) { fprintf (stderr, "pthread_join: %s\n", strerror (err)); exit (EXIT_FAILURE); } /* Clean up. */ if (guestfs_shutdown (destg) == -1) exit (EXIT_FAILURE); guestfs_close (destg); gettimeofday (&end_t, NULL); /* Print the elapsed time. */ ms = timeval_diff (&start_t, &end_t); printf ("copy finished, elapsed time (excluding launch) was " "%" PRIi64 ".%03" PRIi64 " s\n", ms / 1000, ms % 1000); exit (EXIT_SUCCESS); }