mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 20:36:50 +03:00
Ticket #71: support of "Skip all" on multi-file/dir operation.
Added support of skip all failures on file/dir operations. Original patch was created by me <me 0xn0 de> and modified by Thomas Zajic <zlatko gmx at>. Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
parent
371d6c9385
commit
0f1095ea38
@ -466,12 +466,14 @@ static FileProgressStatus
|
||||
warn_same_file (const char *fmt, const char *a, const char *b)
|
||||
{
|
||||
#ifdef WITH_BACKGROUND
|
||||
/* *INDENT-OFF* */
|
||||
union
|
||||
{
|
||||
void *p;
|
||||
FileProgressStatus (*f) (enum OperationMode, const char *fmt,
|
||||
const char *a, const char *b);
|
||||
} pntr;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
pntr.f = real_warn_same_file;
|
||||
|
||||
@ -672,11 +674,16 @@ erase_file (FileOpTotalContext * tctx, FileOpContext * ctx, const char *s,
|
||||
buf.st_size = 0;
|
||||
}
|
||||
|
||||
while (mc_unlink (s) != 0)
|
||||
while (mc_unlink (s) != 0 && !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot delete file \"%s\"\n%s"), s);
|
||||
if (return_status != FILE_RETRY)
|
||||
if (return_status == FILE_ABORT)
|
||||
return return_status;
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tctx->progress_count == 0)
|
||||
@ -686,6 +693,12 @@ erase_file (FileOpTotalContext * tctx, FileOpContext * ctx, const char *s,
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
Recursive remove of files
|
||||
abort->cancel stack
|
||||
skip ->warn every level, gets default
|
||||
skipall->remove as much as possible
|
||||
*/
|
||||
static FileProgressStatus
|
||||
recursive_erase (FileOpTotalContext * tctx, FileOpContext * ctx, const char *s)
|
||||
{
|
||||
@ -703,7 +716,7 @@ recursive_erase (FileOpTotalContext * tctx, FileOpContext * ctx, const char *s)
|
||||
if (!reading)
|
||||
return FILE_RETRY;
|
||||
|
||||
while ((next = mc_readdir (reading)) && return_status == FILE_CONT)
|
||||
while ((next = mc_readdir (reading)) && return_status != FILE_ABORT)
|
||||
{
|
||||
if (!strcmp (next->d_name, "."))
|
||||
continue;
|
||||
@ -717,25 +730,29 @@ recursive_erase (FileOpTotalContext * tctx, FileOpContext * ctx, const char *s)
|
||||
return FILE_RETRY;
|
||||
}
|
||||
if (S_ISDIR (buf.st_mode))
|
||||
return_status =
|
||||
(recursive_erase (tctx, ctx, path) != FILE_CONT) ? FILE_RETRY : FILE_CONT;
|
||||
return_status = recursive_erase (tctx, ctx, path);
|
||||
else
|
||||
return_status = erase_file (tctx, ctx, path, 0);
|
||||
g_free (path);
|
||||
}
|
||||
mc_closedir (reading);
|
||||
if (return_status != FILE_CONT)
|
||||
if (return_status == FILE_ABORT)
|
||||
return return_status;
|
||||
file_progress_show_deleting (ctx, s);
|
||||
if (check_progress_buttons (ctx) == FILE_ABORT)
|
||||
return FILE_ABORT;
|
||||
mc_refresh ();
|
||||
|
||||
while (my_rmdir (s))
|
||||
while (my_rmdir (s) != 0 && !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot remove directory \"%s\"\n%s"), s);
|
||||
if (return_status != FILE_RETRY)
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_ABORT)
|
||||
return return_status;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return FILE_CONT;
|
||||
@ -1069,7 +1086,8 @@ real_do_file_error (enum OperationMode mode, const char *error)
|
||||
const char *msg;
|
||||
|
||||
msg = mode == Foreground ? MSG_ERROR : _("Background process error");
|
||||
result = query_dialog (msg, error, D_ERROR, 3, _("&Skip"), _("&Retry"), _("&Abort"));
|
||||
result =
|
||||
query_dialog (msg, error, D_ERROR, 4, _("&Skip"), _("Ski&p all"), _("&Retry"), _("&Abort"));
|
||||
|
||||
switch (result)
|
||||
{
|
||||
@ -1079,9 +1097,13 @@ real_do_file_error (enum OperationMode mode, const char *error)
|
||||
|
||||
case 1:
|
||||
do_refresh ();
|
||||
return FILE_RETRY;
|
||||
return FILE_SKIPALL;
|
||||
|
||||
case 2:
|
||||
do_refresh ();
|
||||
return FILE_RETRY;
|
||||
|
||||
case 3:
|
||||
default:
|
||||
return FILE_ABORT;
|
||||
}
|
||||
@ -1319,40 +1341,57 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
if (S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode) ||
|
||||
S_ISFIFO (sb.st_mode) || S_ISNAM (sb.st_mode) || S_ISSOCK (sb.st_mode))
|
||||
{
|
||||
while (mc_mknod (dst_path, sb.st_mode & ctx->umask_kill, sb.st_rdev) < 0)
|
||||
while (mc_mknod (dst_path, sb.st_mode & ctx->umask_kill, sb.st_rdev) < 0
|
||||
&& !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot create special file \"%s\"\n%s"), dst_path);
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
return return_status;
|
||||
}
|
||||
/* Success */
|
||||
|
||||
while (ctx->preserve_uidgid && mc_chown (dst_path, sb.st_uid, sb.st_gid))
|
||||
while (ctx->preserve_uidgid && mc_chown (dst_path, sb.st_uid, sb.st_gid) != 0
|
||||
&& !ctx->skip_all)
|
||||
{
|
||||
temp_status = file_error (_("Cannot chown target file \"%s\"\n%s"), dst_path);
|
||||
if (temp_status == FILE_RETRY)
|
||||
continue;
|
||||
return temp_status;
|
||||
if (temp_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
if (temp_status == FILE_SKIP)
|
||||
break;
|
||||
if (temp_status != FILE_RETRY)
|
||||
return temp_status;
|
||||
}
|
||||
while (ctx->preserve && mc_chmod (dst_path, sb.st_mode & ctx->umask_kill))
|
||||
|
||||
while (ctx->preserve && mc_chmod (dst_path, sb.st_mode & ctx->umask_kill) != 0
|
||||
&& !ctx->skip_all)
|
||||
{
|
||||
temp_status = file_error (_("Cannot chmod target file \"%s\"\n%s"), dst_path);
|
||||
if (temp_status == FILE_RETRY)
|
||||
continue;
|
||||
return temp_status;
|
||||
if (temp_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
if (temp_status == FILE_SKIP)
|
||||
break;
|
||||
if (temp_status != FILE_RETRY)
|
||||
return temp_status;
|
||||
}
|
||||
|
||||
return FILE_CONT;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday (&tv_transfer_start, (struct timezone *) NULL);
|
||||
|
||||
while ((src_desc = mc_open (src_path, O_RDONLY | O_LINEAR)) < 0)
|
||||
while ((src_desc = mc_open (src_path, O_RDONLY | O_LINEAR)) < 0 && !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot open source file \"%s\"\n%s"), src_path);
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
if (return_status == FILE_SKIP)
|
||||
break;
|
||||
ctx->do_append = 0;
|
||||
return return_status;
|
||||
}
|
||||
@ -1367,11 +1406,13 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
}
|
||||
}
|
||||
|
||||
while (mc_fstat (src_desc, &sb))
|
||||
while (mc_fstat (src_desc, &sb) != 0 && !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot fstat source file \"%s\"\n%s"), src_path);
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
ctx->do_append = FALSE;
|
||||
goto ret;
|
||||
}
|
||||
@ -1397,12 +1438,14 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
|
||||
while ((dest_desc = mc_open (dst_path, open_flags, src_mode)) < 0)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
if (errno == EEXIST || ctx->skip_all)
|
||||
goto ret;
|
||||
|
||||
return_status = file_error (_("Cannot create target file \"%s\"\n%s"), dst_path);
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
ctx->do_append = FALSE;
|
||||
goto ret;
|
||||
}
|
||||
@ -1412,11 +1455,13 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
ctx->do_append = FALSE;
|
||||
|
||||
/* Find out the optimal buffer size. */
|
||||
while (mc_fstat (dest_desc, &sb))
|
||||
while (mc_fstat (dest_desc, &sb) != 0 && !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot fstat target file \"%s\"\n%s"), dst_path);
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
@ -1448,11 +1493,13 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
if (mc_ctl (src_desc, VFS_CTL_IS_NOTREADY, 0))
|
||||
n_read = -1;
|
||||
else
|
||||
while ((n_read = mc_read (src_desc, buf, sizeof (buf))) < 0)
|
||||
while ((n_read = mc_read (src_desc, buf, sizeof (buf))) < 0 && !ctx->skip_all)
|
||||
{
|
||||
return_status = file_error (_("Cannot read source file\"%s\"\n%s"), src_path);
|
||||
if (return_status == FILE_RETRY)
|
||||
continue;
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
goto ret;
|
||||
}
|
||||
if (n_read == 0)
|
||||
@ -1474,7 +1521,7 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
gettimeofday (&tv_last_input, NULL);
|
||||
|
||||
/* dst_write */
|
||||
while ((n_written = mc_write (dest_desc, t, n_read)) < n_read)
|
||||
while ((n_written = mc_write (dest_desc, t, n_read)) < n_read && !ctx->skip_all)
|
||||
{
|
||||
if (n_written > 0)
|
||||
{
|
||||
@ -1483,6 +1530,10 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
continue;
|
||||
}
|
||||
return_status = file_error (_("Cannot write target file \"%s\"\n%s"), dst_path);
|
||||
if (return_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
if (return_status == FILE_SKIP)
|
||||
break;
|
||||
if (return_status != FILE_RETRY)
|
||||
goto ret;
|
||||
}
|
||||
@ -1536,21 +1587,25 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
dst_status = DEST_FULL; /* copy successful, don't remove target file */
|
||||
|
||||
ret:
|
||||
while (src_desc != -1 && mc_close (src_desc) < 0)
|
||||
while (src_desc != -1 && mc_close (src_desc) < 0 && !ctx->skip_all)
|
||||
{
|
||||
temp_status = file_error (_("Cannot close source file \"%s\"\n%s"), src_path);
|
||||
if (temp_status == FILE_RETRY)
|
||||
continue;
|
||||
if (temp_status == FILE_ABORT)
|
||||
return_status = temp_status;
|
||||
if (temp_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
while (dest_desc != -1 && mc_close (dest_desc) < 0)
|
||||
while (dest_desc != -1 && mc_close (dest_desc) < 0 && !ctx->skip_all)
|
||||
{
|
||||
temp_status = file_error (_("Cannot close target file \"%s\"\n%s"), dst_path);
|
||||
if (temp_status == FILE_RETRY)
|
||||
continue;
|
||||
if (temp_status == FILE_SKIPALL)
|
||||
ctx->skip_all = TRUE;
|
||||
return_status = temp_status;
|
||||
break;
|
||||
}
|
||||
@ -1570,12 +1625,18 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
/* Copy has succeeded */
|
||||
if (!appending && ctx->preserve_uidgid)
|
||||
{
|
||||
while (mc_chown (dst_path, src_uid, src_gid))
|
||||
while (mc_chown (dst_path, src_uid, src_gid) != 0 && !ctx->skip_all)
|
||||
{
|
||||
temp_status = file_error (_("Cannot chown target file \"%s\"\n%s"), dst_path);
|
||||
if (temp_status == FILE_RETRY)
|
||||
continue;
|
||||
return_status = temp_status;
|
||||
if (temp_status == FILE_SKIPALL)
|
||||
{
|
||||
ctx->skip_all = TRUE;
|
||||
return_status = FILE_CONT;
|
||||
}
|
||||
if (temp_status == FILE_SKIP)
|
||||
return_status = FILE_CONT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1584,14 +1645,19 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx,
|
||||
{
|
||||
if (ctx->preserve)
|
||||
{
|
||||
while (mc_chmod (dst_path, (src_mode & ctx->umask_kill)))
|
||||
while (mc_chmod (dst_path, (src_mode & ctx->umask_kill)) != 0 && !ctx->skip_all)
|
||||
{
|
||||
temp_status = file_error (_("Cannot chmod target file \"%s\"\n%s"), dst_path);
|
||||
if (temp_status != FILE_RETRY)
|
||||
if (temp_status == FILE_RETRY)
|
||||
continue;
|
||||
if (temp_status == FILE_SKIPALL)
|
||||
{
|
||||
return_status = temp_status;
|
||||
break;
|
||||
ctx->skip_all = TRUE;
|
||||
return_status = FILE_CONT;
|
||||
}
|
||||
if (temp_status == FILE_SKIP)
|
||||
return_status = FILE_CONT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -78,6 +78,7 @@ file_op_context_new (FileOperation op)
|
||||
ctx->preserve_uidgid = (geteuid () == 0);
|
||||
ctx->umask_kill = 0777777;
|
||||
ctx->erase_at_end = TRUE;
|
||||
ctx->skip_all = FALSE;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ typedef enum
|
||||
FILE_CONT = 0,
|
||||
FILE_RETRY = 1,
|
||||
FILE_SKIP = 2,
|
||||
FILE_ABORT = 3
|
||||
FILE_ABORT = 3,
|
||||
FILE_SKIPALL = 4
|
||||
} FileProgressStatus;
|
||||
|
||||
/* First argument passed to real functions */
|
||||
@ -155,6 +156,9 @@ typedef struct FileOpContext
|
||||
/* PID of the child for background operations */
|
||||
pid_t pid;
|
||||
|
||||
/* toggle if all errors should be ignored */
|
||||
gboolean skip_all;
|
||||
|
||||
/* User interface data goes here */
|
||||
void *ui;
|
||||
} FileOpContext;
|
||||
|
Loading…
Reference in New Issue
Block a user