qopen-in-vm.c 3.4 KB

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