diff --git a/configure.ac b/configure.ac index 2537c5832..933a6afb7 100644 --- a/configure.ac +++ b/configure.ac @@ -138,7 +138,7 @@ fi AC_PROG_INSTALL AC_CHECK_HEADERS([unistd.h string.h memory.h grp.h limits.h malloc.h \ - stdlib.h termios.h utime.h fcntl.h pwd.h sys/statfs.h sys/time.h \ + stdlib.h termios.h utime.h fcntl.h pwd.h sys/statfs.h sys/vfs.h sys/time.h \ sys/timeb.h sys/select.h sys/ioctl.h stropts.h arpa/inet.h \ security/pam_misc.h sys/socket.h sys/sysmacros.h sys/types.h \ sys/mkdev.h wchar.h wctype.h]) diff --git a/src/file.c b/src/file.c index 15d5f70b8..59f2541e9 100644 --- a/src/file.c +++ b/src/file.c @@ -416,6 +416,7 @@ copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path, FileProgressStatus return_status, temp_status; struct timeval tv_transfer_start; int dst_status = DEST_NONE; /* 1 if the file is not fully copied */ + int open_flags; /* FIXME: We should not be using global variables! */ ctx->do_reget = 0; @@ -540,12 +541,19 @@ copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path, utb.modtime = sb.st_mtime; file_size = sb.st_size; - /* Create the new regular file with small permissions initially, - do not create a security hole. FIXME: You have security hole - here, btw. Imagine copying to /tmp and symlink attack :-( */ - - while ((dest_desc = mc_open (dst_path, O_WRONLY | (ctx->do_append ? - O_APPEND : (O_CREAT | O_TRUNC)), 0600)) < 0) { + open_flags = O_WRONLY; + if (dst_exists != 0) { + if (ctx->do_append != 0) + open_flags |= O_APPEND; + else + open_flags |= O_CREAT | O_TRUNC; + } else { + open_flags |= O_CREAT | O_EXCL; + } + while ((dest_desc = mc_open (dst_path, open_flags, src_mode)) < 0) { + if (errno == EEXIST) { + goto ret; + } return_status = file_error ( _(" Cannot create target file \"%s\" \n %s "), dst_path); if (return_status == FILE_RETRY) @@ -724,16 +732,23 @@ copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path, } } - if (!appending && ctx->preserve) { - while (mc_chmod (dst_path, (src_mode & ctx->umask_kill))) { - temp_status = file_error ( + if (!appending) { + if (ctx->preserve){ + while (mc_chmod (dst_path, (src_mode & ctx->umask_kill))) { + temp_status = file_error ( _(" Cannot chmod target file \"%s\" \n %s "), dst_path); - if (temp_status != FILE_RETRY) { - return_status = temp_status; - break; + if (temp_status != FILE_RETRY) { + return_status = temp_status; + break; + } } + mc_utime (dst_path, &utb); + } else { + src_mode = umask(-1); + umask(src_mode); + src_mode = 0100666 & ~src_mode; + mc_chmod (dst_path, (src_mode & ctx->umask_kill)); } - mc_utime (dst_path, &utb); } } @@ -946,6 +961,11 @@ copy_dir_dir (FileOpContext *ctx, const char *s, const char *_d, int toplevel, utb.actime = cbuf.st_atime; utb.modtime = cbuf.st_mtime; mc_utime (dest_dir, &utb); + } else { + cbuf.st_mode = umask(-1); + umask(cbuf.st_mode); + cbuf.st_mode = 0100777 & ~cbuf.st_mode; + mc_chmod (dest_dir, cbuf.st_mode & ctx->umask_kill); } ret: @@ -1763,6 +1783,12 @@ panel_operate (void *source_panel, FileOperation operation, free_linklist (&linklist); free_linklist (&dest_dirs); + /* Update panel contents to avoid actions on deleted files */ + if (!panel->is_panelized) { + update_panels (UP_RELOAD, UP_KEEPSEL); + repaint_screen (); + } + if (single_entry) { if (force_single) { source = selection (panel)->fname; diff --git a/src/filegui.c b/src/filegui.c index d99970bd2..2b0f390f9 100644 --- a/src/filegui.c +++ b/src/filegui.c @@ -1,7 +1,7 @@ /* File management GUI for the text mode edition * * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, - * 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + * 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. * * Written by: 1994, 1995 Janne Kukonlehto * 1994, 1995 Fred Leeflang @@ -9,6 +9,7 @@ * 1995, 1996 Jakub Jelinek * 1997 Norbert Warmuth * 1998 Pavel Machek + * 2009 Slava Zanko * * The copy code was based in GNU's cp, and was written by: * Torbjorn Granlund, David MacKenzie, and Jim Meyering. @@ -53,6 +54,22 @@ #include #include #include + +#if defined (__FreeBSD__) +# include +#endif +#if defined(__APPLE__) || defined (__FreeBSD__) +# include +#elif defined (__NetBSD__) +# include +#else +# ifdef HAVE_VFS +# include +# else +# include +# endif +#endif + #include #include "global.h" @@ -73,6 +90,15 @@ #include "../src/strescape.h" /* }}} */ +typedef enum { + MSDOS_SUPER_MAGIC = 0x4d44, + NTFS_SB_MAGIC = 0x5346544e, + NTFS_3G_MAGIC = 0x65735546, + PROC_SUPER_MAGIC = 0x9fa0, + SMB_SUPER_MAGIC = 0x517B, + NCP_SUPER_MAGIC = 0x564c, + USBDEVICE_SUPER_MAGIC = 0x9fa2 +} filegui_nonattrs_fs_t; /* Hack: the vfs code should not rely on this */ #define WITH_FULL_PATHS 1 @@ -133,6 +159,29 @@ enum { REPLACE_REGET }; +static int +filegui__check_attrs_on_fs(const char *fs_path) +{ + struct statfs stfs; + + if (statfs(fs_path, &stfs)!=0) + return 1; + + switch ((filegui_nonattrs_fs_t) stfs.f_type) + { + case MSDOS_SUPER_MAGIC: + case NTFS_SB_MAGIC: + case NTFS_3G_MAGIC: + case PROC_SUPER_MAGIC: + case SMB_SUPER_MAGIC: + case NCP_SUPER_MAGIC: + case USBDEVICE_SUPER_MAGIC: + return 0; + break; + } + return 1; +} + static FileProgressStatus check_progress_buttons (FileOpContext *ctx) { @@ -873,6 +922,10 @@ file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, fmd_init_i18n (FALSE); + + /* unselect checkbox if target filesystem don't support attributes */ + ctx->op_preserve = filegui__check_attrs_on_fs(def_text); + /* Set up the result pointers */ fmd_widgets[FMCB12].result = &ctx->op_preserve;