8da7c7af60
The qvm-{copy,move}-to-vm.{gnome,kde} cancel buttons didn't actually cancel, because qfile-agent ignored EPIPE and - via qfile_pack_init() - SIGPIPE. So it never noticed when the local PROGRESS_TYPE=gui reader had shut down.
121 lines
3.2 KiB
C
121 lines
3.2 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 <unistd.h>
|
|
#include <errno.h>
|
|
#include <gui-fatal.h>
|
|
#include <libqubes-rpc-filecopy.h>
|
|
|
|
enum {
|
|
PROGRESS_FLAG_NORMAL,
|
|
PROGRESS_FLAG_INIT,
|
|
PROGRESS_FLAG_DONE
|
|
};
|
|
|
|
void do_notify_progress(long long total, int flag)
|
|
{
|
|
const char *du_size_env = getenv("FILECOPY_TOTAL_SIZE");
|
|
const char *progress_type_env = getenv("PROGRESS_TYPE");
|
|
const char *saved_stdout_env = getenv("SAVED_FD_1");
|
|
int ignore;
|
|
if (!progress_type_env)
|
|
return;
|
|
if (!strcmp(progress_type_env, "console") && du_size_env) {
|
|
char msg[256];
|
|
snprintf(msg, sizeof(msg), "sent %lld/%lld KB\r",
|
|
total / 1024, strtoull(du_size_env, NULL, 0));
|
|
ignore = write(2, msg, strlen(msg));
|
|
if (flag == PROGRESS_FLAG_DONE)
|
|
ignore = write(2, "\n", 1);
|
|
if (ignore < 0) {
|
|
/* silence gcc warning */
|
|
}
|
|
}
|
|
if (!strcmp(progress_type_env, "gui") && saved_stdout_env) {
|
|
char msg[256];
|
|
snprintf(msg, sizeof(msg), "%lld\n", total);
|
|
if (write(strtoul(saved_stdout_env, NULL, 0), msg, strlen(msg)) == -1
|
|
&& errno == EPIPE)
|
|
exit(32);
|
|
}
|
|
}
|
|
|
|
void notify_progress(int size, int flag)
|
|
{
|
|
static long long total = 0;
|
|
static long long prev_total = 0;
|
|
total += size;
|
|
if (total > prev_total + PROGRESS_NOTIFY_DELTA
|
|
|| (flag != PROGRESS_FLAG_NORMAL)) {
|
|
// check for possible error from qfile-unpacker; if error occured,
|
|
// exit() will be called, so don't bother with current state
|
|
// (notify_progress can be called as callback from copy_file())
|
|
if (flag == PROGRESS_FLAG_NORMAL)
|
|
wait_for_result();
|
|
do_notify_progress(total, flag);
|
|
prev_total = total;
|
|
}
|
|
}
|
|
|
|
|
|
char *get_abs_path(const char *cwd, const char *pathname)
|
|
{
|
|
char *ret;
|
|
if (pathname[0] == '/')
|
|
return strdup(pathname);
|
|
if (asprintf(&ret, "%s/%s", cwd, pathname) < 0)
|
|
return NULL;
|
|
else
|
|
return ret;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i;
|
|
char *entry;
|
|
char *cwd;
|
|
char *sep;
|
|
int ignore_symlinks = 0;
|
|
|
|
qfile_pack_init();
|
|
register_error_handler(qfile_gui_fatal);
|
|
register_notify_progress(¬ify_progress);
|
|
notify_progress(0, PROGRESS_FLAG_INIT);
|
|
cwd = getcwd(NULL, 0);
|
|
for (i = 1; i < argc; i++) {
|
|
if (strcmp(argv[i], "--ignore-symlinks")==0) {
|
|
ignore_symlinks = 1;
|
|
continue;
|
|
}
|
|
|
|
entry = get_abs_path(cwd, argv[i]);
|
|
|
|
do {
|
|
sep = rindex(entry, '/');
|
|
if (!sep)
|
|
gui_fatal
|
|
("Internal error: nonabsolute filenames not allowed");
|
|
*sep = 0;
|
|
} while (sep[1] == 0);
|
|
if (entry[0] == 0) {
|
|
if (chdir("/") < 0) {
|
|
gui_fatal("Internal error: chdir(\"/\") failed?!");
|
|
}
|
|
} else if (chdir(entry))
|
|
gui_fatal("chdir to %s", entry);
|
|
do_fs_walk(sep + 1, ignore_symlinks);
|
|
free(entry);
|
|
}
|
|
notify_end_and_wait_for_result();
|
|
notify_progress(0, PROGRESS_FLAG_DONE);
|
|
return 0;
|
|
}
|
|
|
|
|