From 81f5b5e0b89627813f042902d4cff3cfc7dc88f7 Mon Sep 17 00:00:00 2001 From: Alexander Moiseenko Date: Tue, 20 Oct 2009 00:30:55 +0300 Subject: [PATCH] Ticket #1500: Segmentation fault while background copying Test case: * create file with name "test" in "tmp" directory (for example) * create directory with same name ("test") in other "tmp2" directory (for example) * try to copy or move file "test" into "tmp2" in background mode * wait for some time Signed-off-by: Slava Zanko --- src/background.c | 56 +++++++++++++++++++++++++++++++++--------------- src/background.h | 1 + src/file.c | 35 ++++++++++++++++++++++++++++-- 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/background.c b/src/background.c index 4bd2d2cc5..2ec345bc2 100644 --- a/src/background.c +++ b/src/background.c @@ -61,6 +61,9 @@ int we_are_background = 0; /* File descriptor for talking to our parent */ static int parent_fd; +/* File descriptor for messages from our parent */ +static int from_parent_fd; + #define MAXCALLARGS 4 /* Number of arguments supported */ struct TaskList *task_list = NULL; @@ -68,7 +71,8 @@ struct TaskList *task_list = NULL; static int background_attention (int fd, void *closure); static void -register_task_running (FileOpContext *ctx, pid_t pid, int fd, char *info) +register_task_running (FileOpContext *ctx, pid_t pid, int fd, int to_child, + char *info) { TaskList *new; @@ -78,6 +82,7 @@ register_task_running (FileOpContext *ctx, pid_t pid, int fd, char *info) new->state = Task_Running; new->next = task_list; new->fd = fd; + new->to_child_fd = to_child; task_list = new; add_select_channel (fd, background_attention, ctx); @@ -117,24 +122,31 @@ int do_background (struct FileOpContext *ctx, char *info) { int comm[2]; /* control connection stream */ + int back_comm[2]; /* back connection */ pid_t pid; if (pipe (comm) == -1) return -1; + if (pipe (back_comm) == -1) + return -1; + if ((pid = fork ()) == -1) { - int saved_errno = errno; - (void) close (comm[0]); - (void) close (comm[1]); - errno = saved_errno; + int saved_errno = errno; + (void) close (comm[0]); + (void) close (comm[1]); + (void) close (back_comm[0]); + (void) close (back_comm[1]); + errno = saved_errno; return -1; } if (pid == 0) { int nullfd; - close (comm[0]); parent_fd = comm[1]; + from_parent_fd = back_comm[0]; + we_are_background = 1; current_dlg = NULL; @@ -151,9 +163,8 @@ do_background (struct FileOpContext *ctx, char *info) return 0; } else { - close (comm[1]); ctx->pid = pid; - register_task_running (ctx, pid, comm[0], info); + register_task_running (ctx, pid, comm[0], back_comm[1], info); return 1; } } @@ -226,6 +237,8 @@ background_attention (int fd, void *closure) int argc, i, result, status; char *data [MAXCALLARGS]; ssize_t bytes; + struct TaskList *p; + int to_child_fd; enum ReturnType type; ctx = closure; @@ -305,10 +318,18 @@ background_attention (int fd, void *closure) break; } + /* Find child task info by descriptor */ + for (p = task_list; p; p = p->next) { + if (p->fd == fd) + break; + } + + to_child_fd = p->to_child_fd; + /* Send the result code and the value for shared variables */ - write (fd, &result, sizeof (int)); + write (to_child_fd, &result, sizeof (int)); if (have_ctx) - write (fd, ctx, sizeof (FileOpContext)); + write (to_child_fd, ctx, sizeof (FileOpContext)); } else if (type == Return_String) { int len; char *resstr = NULL; @@ -333,14 +354,14 @@ background_attention (int fd, void *closure) } if (resstr){ len = strlen (resstr); - write (fd, &len, sizeof (len)); + write (to_child_fd, &len, sizeof (len)); if (len){ - write (fd, resstr, len); + write (to_child_fd, resstr, len); g_free (resstr); } } else { len = 0; - write (fd, &len, sizeof (len)); + write (to_child_fd, &len, sizeof (len)); } } for (i = 0; i < argc; i++) @@ -392,9 +413,10 @@ parent_call (void *routine, struct FileOpContext *ctx, int argc, ...) write (parent_fd, &len, sizeof (int)); write (parent_fd, value, len); } - read (parent_fd, &i, sizeof (int)); + + read (from_parent_fd, &i, sizeof (int)); if (ctx) - read (parent_fd, ctx, sizeof (FileOpContext)); + read (from_parent_fd, ctx, sizeof (FileOpContext)); return i; } @@ -417,11 +439,11 @@ parent_call_string (void *routine, int argc, ...) write (parent_fd, &len, sizeof (int)); write (parent_fd, value, len); } - read (parent_fd, &i, sizeof (int)); + read (from_parent_fd, &i, sizeof (int)); if (!i) return NULL; str = g_malloc (i + 1); - read (parent_fd, str, i); + read (from_parent_fd, str, i); str [i] = 0; return str; } diff --git a/src/background.h b/src/background.h index 266240d65..8ad4d54a9 100644 --- a/src/background.h +++ b/src/background.h @@ -17,6 +17,7 @@ enum TaskState { typedef struct TaskList { int fd; + int to_child_fd; pid_t pid; int state; char *info; diff --git a/src/file.c b/src/file.c index 55e167e65..909c8cdea 100644 --- a/src/file.c +++ b/src/file.c @@ -381,12 +381,18 @@ enum { }; static FileProgressStatus -warn_same_file (const char *fmt, const char *a, const char *b) +real_warn_same_file (enum OperationMode mode, const char *fmt, + const char *a, const char *b) { char *msg; int result = 0; + const char *head_msg; + + head_msg = mode == Foreground ? MSG_ERROR : + _(" Background process error "); + msg = g_strdup_printf (fmt, a, b); - result = query_dialog (MSG_ERROR, msg, D_ERROR, 2, _("&Skip"), _("&Abort")); + result = query_dialog (head_msg, msg, D_ERROR, 2, _("&Skip"), _("&Abort")); g_free(msg); do_refresh (); if ( result ) { /* 1 == Abort */ @@ -396,6 +402,31 @@ warn_same_file (const char *fmt, const char *a, const char *b) } } +#ifdef WITH_BACKGROUND +static FileProgressStatus +warn_same_file (const char *fmt, const char *a, const char *b) +{ + union { + void *p; + FileProgressStatus (*f) (enum OperationMode, const char *fmt, + const char *a, const char *b); + } pntr; + pntr.f = real_warn_same_file; + + if (we_are_background) + return parent_call (pntr.p, NULL, 3, strlen (fmt), + fmt, strlen(a), a, strlen(b), b); + else + return real_warn_same_file (Foreground, fmt, a, b); +} +#else +static FileProgressStatus +warn_same_file (const char *fmt, const char *a, const char *b) +{ + return real_warn_same_file (Foreground, fmt, a, b); +} +#endif + FileProgressStatus copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path, int ask_overwrite, off_t *progress_count,