42b1355957
This will cause most applications to disallow changing the file and also add some visual indication about the view being read only. This will avoid making the changes that would be discarded later. QubesOS/qubes-issues#1118
133 lines
3.3 KiB
C
133 lines
3.3 KiB
C
#define _GNU_SOURCE
|
|
#include <dirent.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include <malloc.h>
|
|
#include <stdlib.h>
|
|
#include <libqubes-rpc-filecopy.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <gui-fatal.h>
|
|
#include "dvm2.h"
|
|
|
|
void send_file(const char *fname, int view_only)
|
|
{
|
|
const char *base;
|
|
char sendbuf[DVM_FILENAME_SIZE] = {0};
|
|
size_t sendbuf_size = DVM_FILENAME_SIZE;
|
|
int fd = open(fname, O_RDONLY);
|
|
if (fd < 0)
|
|
gui_fatal("open %s", fname);
|
|
if (view_only) {
|
|
strncpy(sendbuf, DVM_VIEW_ONLY_PREFIX, sendbuf_size);
|
|
sendbuf_size -= strlen(DVM_VIEW_ONLY_PREFIX);
|
|
}
|
|
base = rindex(fname, '/');
|
|
if (!base)
|
|
base = fname;
|
|
else
|
|
base++;
|
|
if (strlen(base) >= sendbuf_size)
|
|
base += strlen(base) - sendbuf_size + 1;
|
|
strncat(sendbuf,base,sendbuf_size - 1); /* fills out with NULs */
|
|
sendbuf[DVM_FILENAME_SIZE - 1] = '\0';
|
|
if (!write_all(1, sendbuf, DVM_FILENAME_SIZE))
|
|
gui_fatal("send filename to dispVM");
|
|
if (!copy_fd_all(1, fd))
|
|
gui_fatal("send file to dispVM");
|
|
close(1);
|
|
close(fd);
|
|
}
|
|
|
|
int copy_and_return_nonemptiness(int tmpfd)
|
|
{
|
|
struct stat st;
|
|
if (!copy_fd_all(tmpfd, 0))
|
|
gui_fatal("receiving file from dispVM");
|
|
if (fstat(tmpfd, &st))
|
|
gui_fatal("fstat");
|
|
close(tmpfd);
|
|
|
|
return st.st_size > 0;
|
|
}
|
|
|
|
void recv_file_nowrite(const char *fname)
|
|
{
|
|
char *tempfile;
|
|
char *errmsg;
|
|
int tmpfd = -1;
|
|
|
|
if (asprintf(&tempfile, "/tmp/file_edited_in_dvm.XXXXXX") != -1)
|
|
tmpfd = mkstemp(tempfile);
|
|
if (tmpfd < 0)
|
|
gui_fatal("unable to create any temporary file, aborting");
|
|
if (!copy_and_return_nonemptiness(tmpfd)) {
|
|
unlink(tempfile);
|
|
return;
|
|
}
|
|
if (asprintf(&errmsg,
|
|
"The file %s has been edited in Disposable VM and the modified content has been received, "
|
|
"but this file is in nonwritable directory and thus cannot be modified safely. The edited file has been "
|
|
"saved to %s", fname, tempfile) != -1)
|
|
gui_nonfatal(errmsg);
|
|
}
|
|
|
|
void actually_recv_file(const char *fname, const char *tempfile, int tmpfd)
|
|
{
|
|
if (!copy_and_return_nonemptiness(tmpfd)) {
|
|
unlink(tempfile);
|
|
return;
|
|
}
|
|
if (rename(tempfile, fname))
|
|
gui_fatal("rename");
|
|
}
|
|
|
|
void recv_file(const char *fname)
|
|
{
|
|
int tmpfd = -1;
|
|
char *tempfile;
|
|
if (asprintf(&tempfile, "%s.XXXXXX", fname) != -1) {
|
|
tmpfd = mkstemp(tempfile);
|
|
}
|
|
if (tmpfd < 0)
|
|
recv_file_nowrite(fname);
|
|
else
|
|
actually_recv_file(fname, tempfile, tmpfd);
|
|
}
|
|
|
|
int main(int argc, char ** argv)
|
|
{
|
|
char *fname;
|
|
int view_only = 0;
|
|
int ret;
|
|
const struct option opts[] = {
|
|
{"view-only", no_argument, &view_only, 1},
|
|
{0}
|
|
};
|
|
|
|
while ((ret=getopt_long(argc, argv, "", opts, NULL)) != -1) {
|
|
if (ret == '?') {
|
|
exit(2);
|
|
}
|
|
}
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
if (optind >= argc)
|
|
gui_fatal("OpenInVM - no file given?");
|
|
fname = argv[optind];
|
|
send_file(fname, view_only);
|
|
if (!view_only) {
|
|
recv_file(fname);
|
|
} else {
|
|
/* discard received data */
|
|
int null_fd = open("/dev/null", O_WRONLY);
|
|
copy_fd_all(null_fd, 0);
|
|
close(null_fd);
|
|
}
|
|
return 0;
|
|
}
|