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;
 | 
						|
}
 | 
						|
 | 
						|
 |