qopen-in-vm.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #define _GNU_SOURCE
  2. #include <dirent.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/stat.h>
  6. #include <signal.h>
  7. #include <fcntl.h>
  8. #include <malloc.h>
  9. #include <stdlib.h>
  10. #include <libqubes-rpc-filecopy.h>
  11. #include <unistd.h>
  12. #include <getopt.h>
  13. #include <gui-fatal.h>
  14. #include "dvm2.h"
  15. void send_file(const char *fname, int view_only)
  16. {
  17. const char *base;
  18. char sendbuf[DVM_FILENAME_SIZE] = {0};
  19. size_t sendbuf_size = DVM_FILENAME_SIZE;
  20. int fd = open(fname, O_RDONLY);
  21. if (fd < 0)
  22. gui_fatal("open %s", fname);
  23. if (view_only) {
  24. strncpy(sendbuf, DVM_VIEW_ONLY_PREFIX, sendbuf_size);
  25. sendbuf_size -= strlen(DVM_VIEW_ONLY_PREFIX);
  26. }
  27. base = rindex(fname, '/');
  28. if (!base)
  29. base = fname;
  30. else
  31. base++;
  32. if (strlen(base) >= sendbuf_size)
  33. base += strlen(base) - sendbuf_size + 1;
  34. strncat(sendbuf,base,sendbuf_size - 1); /* fills out with NULs */
  35. sendbuf[DVM_FILENAME_SIZE - 1] = '\0';
  36. if (!write_all(1, sendbuf, DVM_FILENAME_SIZE))
  37. gui_fatal("send filename to dispVM");
  38. if (!copy_fd_all(1, fd))
  39. gui_fatal("send file to dispVM");
  40. close(1);
  41. close(fd);
  42. }
  43. int copy_and_return_nonemptiness(int tmpfd)
  44. {
  45. struct stat st;
  46. if (!copy_fd_all(tmpfd, 0))
  47. gui_fatal("receiving file from dispVM");
  48. if (fstat(tmpfd, &st))
  49. gui_fatal("fstat");
  50. close(tmpfd);
  51. return st.st_size > 0;
  52. }
  53. void recv_file_nowrite(const char *fname)
  54. {
  55. char *tempfile;
  56. char *errmsg;
  57. int tmpfd = -1;
  58. if (asprintf(&tempfile, "/tmp/file_edited_in_dvm.XXXXXX") != -1)
  59. tmpfd = mkstemp(tempfile);
  60. if (tmpfd < 0)
  61. gui_fatal("unable to create any temporary file, aborting");
  62. if (!copy_and_return_nonemptiness(tmpfd)) {
  63. unlink(tempfile);
  64. return;
  65. }
  66. if (asprintf(&errmsg,
  67. "The file %s has been edited in Disposable VM and the modified content has been received, "
  68. "but this file is in nonwritable directory and thus cannot be modified safely. The edited file has been "
  69. "saved to %s", fname, tempfile) != -1)
  70. gui_nonfatal(errmsg);
  71. }
  72. void actually_recv_file(const char *fname, const char *tempfile, int tmpfd)
  73. {
  74. if (!copy_and_return_nonemptiness(tmpfd)) {
  75. unlink(tempfile);
  76. return;
  77. }
  78. if (rename(tempfile, fname))
  79. gui_fatal("rename");
  80. }
  81. void recv_file(const char *fname)
  82. {
  83. int tmpfd = -1;
  84. char *tempfile;
  85. if (asprintf(&tempfile, "%s.XXXXXX", fname) != -1) {
  86. tmpfd = mkstemp(tempfile);
  87. }
  88. if (tmpfd < 0)
  89. recv_file_nowrite(fname);
  90. else
  91. actually_recv_file(fname, tempfile, tmpfd);
  92. }
  93. int main(int argc, char ** argv)
  94. {
  95. char *fname;
  96. int view_only = 0;
  97. int ret;
  98. const struct option opts[] = {
  99. {"view-only", no_argument, &view_only, 1},
  100. {0}
  101. };
  102. while ((ret=getopt_long(argc, argv, "", opts, NULL)) != -1) {
  103. if (ret == '?') {
  104. exit(2);
  105. }
  106. }
  107. signal(SIGPIPE, SIG_IGN);
  108. if (optind >= argc)
  109. gui_fatal("OpenInVM - no file given?");
  110. fname = argv[optind];
  111. send_file(fname, view_only);
  112. if (!view_only) {
  113. recv_file(fname);
  114. } else {
  115. /* discard received data */
  116. int null_fd = open("/dev/null", O_WRONLY);
  117. copy_fd_all(null_fd, 0);
  118. close(null_fd);
  119. }
  120. return 0;
  121. }