From f6f7c8c1ce0015284e97fc4b286ad1bbb87d62a0 Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Sun, 17 Mar 2024 13:25:37 +0300 Subject: [PATCH 1/2] Ticket #4451: preserve ext2fs attributes on copy/move operations. Signed-off-by: Andrew Borodin --- src/filemanager/file.c | 140 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/src/filemanager/file.c b/src/filemanager/file.c index 4e1f2c970c..cafa451c60 100644 --- a/src/filemanager/file.c +++ b/src/filemanager/file.c @@ -2272,6 +2272,8 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, mode_t src_mode = 0; /* The mode of the source file */ struct stat src_stat, dst_stat; mc_timesbuf_t times; + unsigned long attrs; + gboolean attrs_ok = ctx->preserve; gboolean dst_exists = FALSE, appending = FALSE; off_t file_size = -1; FileProgressStatus return_status, temp_status; @@ -2336,6 +2338,30 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, goto ret_fast; } + while (attrs_ok && mc_fgetflags (src_vpath, &attrs) != 0) + { + attrs_ok = FALSE; + + /* don't show an error message if attributes aren't supported in this FS */ + if (errno == ENOTSUP) + return_status = FILE_CONT; + else if (ctx->skip_all) + return_status = FILE_SKIPALL; + else + { + return_status = + file_error (TRUE, _("Cannot get attributes of source file \"%s\"\n%s"), src_path); + if (return_status == FILE_SKIPALL) + ctx->skip_all = TRUE; + } + + if (return_status != FILE_RETRY) + break; + + /* yet another attempt */ + attrs_ok = TRUE; + } + if (dst_exists) { /* Destination already exists */ @@ -2379,7 +2405,30 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, { return_status = make_symlink (ctx, src_vpath, dst_vpath); if (return_status == FILE_CONT && ctx->preserve) + { mc_utime (dst_vpath, ×); + + while (attrs_ok && mc_fsetflags (dst_vpath, attrs) != 0 && !ctx->skip_all) + { + attrs_ok = FALSE; + + /* don't show an error message if attributes aren't supported in this FS */ + if (errno == ENOTSUP) + return_status = FILE_CONT; + else if (return_status == FILE_SKIPALL) + ctx->skip_all = TRUE; + else + return_status = + file_error (TRUE, _("Cannot set attributes of target file \"%s\"\n%s"), + dst_path); + + if (return_status != FILE_RETRY) + break; + + /* yet another attempt */ + attrs_ok = TRUE; + } + } goto ret_fast; } @@ -2435,6 +2484,31 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, } } + while (attrs_ok && mc_fsetflags (dst_vpath, attrs) != 0 && !ctx->skip_all) + { + attrs_ok = FALSE; + + /* don't show an error message if attributes aren't supported in this FS */ + if (errno == ENOTSUP) + break; + + temp_status = + file_error (TRUE, _("Cannot set attributes of target file \"%s\"\n%s"), + dst_path); + if (temp_status == FILE_SKIP) + break; + if (temp_status == FILE_SKIPALL) + ctx->skip_all = TRUE; + if (temp_status != FILE_RETRY) + { + return_status = temp_status; + goto ret_fast; + } + + /* yet another attempt */ + attrs_ok = TRUE; + } + return_status = FILE_CONT; mc_utime (dst_vpath, ×); goto ret_fast; @@ -2817,10 +2891,40 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, } } - /* Always sync timestamps */ if (dst_status == DEST_FULL || dst_status == DEST_SHORT_KEEP) + { + /* Always sync timestamps */ mc_utime (dst_vpath, ×); + while (attrs_ok && mc_fsetflags (dst_vpath, attrs) != 0 && !ctx->skip_all) + { + attrs_ok = FALSE; + + /* don't show an error message if attributes aren't supported in this FS */ + if (errno == ENOTSUP) + { + return_status = FILE_CONT; + break; + } + + temp_status = file_error (TRUE, _("Cannot set attributes for target file \"%s\"\n%s"), + dst_path); + if (temp_status == FILE_RETRY) + { + attrs_ok = TRUE; + continue; + } + if (temp_status == FILE_SKIPALL) + { + ctx->skip_all = TRUE; + return_status = FILE_CONT; + } + if (temp_status == FILE_SKIP) + return_status = FILE_CONT; + break; + } + } + if (return_status == FILE_CONT) return_status = progress_update_one (tctx, ctx, file_size); @@ -2844,6 +2948,8 @@ copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const cha { struct vfs_dirent *next; struct stat dst_stat, src_stat; + unsigned long attrs; + gboolean attrs_ok = ctx->preserve; DIR *reading; FileProgressStatus return_status = FILE_CONT; struct link *lp; @@ -2871,6 +2977,34 @@ copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const cha goto ret_fast; } + while (attrs_ok && mc_fgetflags (src_vpath, &attrs) != 0) + { + attrs_ok = FALSE; + + /* don't show an error message if attributes aren't supported in this FS */ + if (errno == ENOTSUP) + { + return_status = FILE_CONT; + break; + } + + if (ctx->skip_all) + return_status = FILE_SKIPALL; + else + { + return_status = + file_error (TRUE, _("Cannot get attributes of source directory \"%s\"\n%s"), s); + if (return_status == FILE_RETRY) + { + attrs_ok = TRUE; + continue; + } + if (return_status == FILE_SKIPALL) + ctx->skip_all = TRUE; + } + goto ret_fast; + } + if (is_in_linklist (dest_dirs, src_vpath, &src_stat) != NULL) { /* Don't copy a directory we created before (we don't want to copy @@ -3097,6 +3231,10 @@ copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const cha mc_timesbuf_t times; mc_chmod (dst_vpath, src_stat.st_mode & ctx->umask_kill); + + if (attrs_ok) + mc_fsetflags (dst_vpath, attrs); + get_times (&src_stat, ×); mc_utime (dst_vpath, ×); } From 16fadb9d029f53fcb039390ac818c5033cc2c3ab Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Sat, 16 Mar 2024 21:01:50 +0300 Subject: [PATCH 2/2] mceditor: support ext2fs attributes. Get attributes on file open and set ones on file save. Signed-off-by: Andrew Borodin --- src/editor/edit.c | 2 ++ src/editor/editcmd.c | 2 ++ src/editor/editwidget.h | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/editor/edit.c b/src/editor/edit.c index 2eceeedf89..8846b2fdc2 100644 --- a/src/editor/edit.c +++ b/src/editor/edit.c @@ -2164,6 +2164,8 @@ edit_init (WEdit * edit, const WRect * r, const vfs_path_t * filename_vpath, lon edit->stat1.st_gid = getgid (); edit->stat1.st_mtime = 0; + edit->attrs_ok = (mc_fgetflags (filename_vpath, &edit->attrs) == 0); + edit->over_col = 0; edit->bracket = -1; edit->last_bracket = -1; diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c index bca9df7778..32144b1233 100644 --- a/src/editor/editcmd.c +++ b/src/editor/editcmd.c @@ -239,6 +239,8 @@ edit_save_file (WEdit * edit, const vfs_path_t * filename_vpath) (void) mc_chown (savename_vpath, edit->stat1.st_uid, edit->stat1.st_gid); (void) mc_chmod (savename_vpath, edit->stat1.st_mode); + if (edit->attrs_ok) + (void) mc_fsetflags (savename_vpath, edit->attrs); fd = mc_open (savename_vpath, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode); if (fd == -1) diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h index 769b91a1e8..d178f00f3a 100644 --- a/src/editor/editwidget.h +++ b/src/editor/editwidget.h @@ -150,6 +150,9 @@ struct WEdit unsigned int redo_stack_reset:1; /* If 1, need clear redo stack */ struct stat stat1; /* Result of mc_fstat() on the file */ + unsigned long attrs; /* Result of mc_fgetflags() on the file */ + gboolean attrs_ok; /* mc_fgetflags() == 0 */ + unsigned int skip_detach_prompt:1; /* Do not prompt whether to detach a file anymore */ /* syntax highlighting */