Ticket #3575: 0001-Ticket-3575-preserve-timestamps-with-nanosecond-prec.patch

File 0001-Ticket-3575-preserve-timestamps-with-nanosecond-prec.patch, 11.6 KB (added by ag, 8 years ago)

Proposed fix

  • configure.ac

    From e6f9635425c94c37593858f0f15da4f1f54b3ba3 Mon Sep 17 00:00:00 2001
    From: Andrey Gursky <andrey.gursky@e-mail.ua>
    Date: Mon, 7 Dec 2015 00:39:05 +0100
    Subject: [PATCH] Ticket #3575: preserve timestamps with nanosecond precisions
     during file copy
    
    MC truncates timestamps during file copy and drops sub-second precision.
    
    Make use of utimensat(), introduced in Linux kernel 2.6.22 (and since
    2.6.26 compatible with POSIX-1.2008).
    
    Signed-off-by: Andrey Gursky <andrey.gursky@e-mail.ua>
    ---
     configure.ac               |  3 +++
     lib/vfs/interface.c        |  2 +-
     lib/vfs/vfs.h              | 14 ++++++++++---
     src/filemanager/file.c     | 28 ++++++++++++++++++--------
     src/vfs/fish/fish.c        | 49 ++++++++++++++++++++++++++++++++++++++--------
     src/vfs/local/local.c      | 10 ++++++++--
     src/vfs/sfs/sfs.c          | 11 +++++++++--
     src/vfs/sftpfs/vfs_class.c |  2 +-
     src/vfs/smbfs/smbfs.c      |  6 +++++-
     9 files changed, 99 insertions(+), 26 deletions(-)
    
    diff --git a/configure.ac b/configure.ac
    index 91be803..a5a850f 100644
    a b AC_CHECK_FUNCS([\ 
    228228        realpath 
    229229]) 
    230230 
     231dnl utimensat is supported since glibc 2.6 and specified in POSIX.1-2008 
     232AC_CHECK_FUNCS([utimensat]) 
     233 
    231234dnl getpt is a GNU Extension (glibc 2.1.x) 
    232235AC_CHECK_FUNCS(posix_openpt, , [AC_CHECK_FUNCS(getpt)]) 
    233236AC_CHECK_FUNCS(grantpt, , [AC_CHECK_LIB(pt, grantpt)]) 
  • lib/vfs/interface.c

    diff --git a/lib/vfs/interface.c b/lib/vfs/interface.c
    index 550fbef..74d3343 100644
    a b int mc_##name inarg \ 
    247247 
    248248MC_NAMEOP (chmod, (const vfs_path_t *vpath, mode_t mode), (vpath, mode)) 
    249249MC_NAMEOP (chown, (const vfs_path_t *vpath, uid_t owner, gid_t group), (vpath, owner, group)) 
    250 MC_NAMEOP (utime, (const vfs_path_t *vpath, struct utimbuf * times), (vpath, times)) 
     250MC_NAMEOP (utime, (const vfs_path_t *vpath, const timesbuf_st *times), (vpath, times)) 
    251251MC_NAMEOP (readlink, (const vfs_path_t *vpath, char *buf, size_t bufsiz), (vpath, buf, bufsiz)) 
    252252MC_NAMEOP (unlink, (const vfs_path_t *vpath), (vpath)) 
    253253MC_NAMEOP (mkdir, (const vfs_path_t *vpath, mode_t mode), (vpath, mode)) 
  • lib/vfs/vfs.h

    diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h
    index ab6f7a2..ade1bb7 100644
    a b  
    1010#include <sys/types.h> 
    1111#include <sys/stat.h> 
    1212#include <dirent.h> 
    13 #ifdef HAVE_UTIME_H 
     13#ifdef HAVE_UTIMENSAT 
     14#include <sys/time.h> 
     15#elif defined( HAVE_UTIME_H ) 
    1416#include <utime.h> 
    1517#endif 
    1618#include <stdio.h> 
    typedef void (*fill_names_f) (const char *); 
    9799 
    98100typedef void *vfsid; 
    99101 
     102#ifdef HAVE_UTIMENSAT 
     103typedef struct timespec timesbuf_st[2]; 
     104#else 
     105typedef struct utimbuf timesbuf_st; 
     106#endif 
     107 
    100108/*** enums ***************************************************************************************/ 
    101109 
    102110/* Flags of VFS classes */ 
    typedef struct vfs_class 
    167175 
    168176    int (*chmod) (const vfs_path_t * vpath, mode_t mode); 
    169177    int (*chown) (const vfs_path_t * vpath, uid_t owner, gid_t group); 
    170     int (*utime) (const vfs_path_t * vpath, struct utimbuf * times); 
     178    int (*utime) (const vfs_path_t * vpath, const timesbuf_st *times); 
    171179 
    172180    int (*readlink) (const vfs_path_t * vpath, char *buf, size_t size); 
    173181    int (*symlink) (const vfs_path_t * vpath1, const vfs_path_t * vpath2); 
    int vfs_preallocate (int dest_desc, off_t src_fsize, off_t dest_fsize); 
    281289 */ 
    282290ssize_t mc_read (int handle, void *buffer, size_t count); 
    283291ssize_t mc_write (int handle, const void *buffer, size_t count); 
    284 int mc_utime (const vfs_path_t * vpath, struct utimbuf *times); 
     292int mc_utime (const vfs_path_t * vpath, const timesbuf_st *times); 
    285293int mc_readlink (const vfs_path_t * vpath, char *buf, size_t bufsiz); 
    286294int mc_close (int handle); 
    287295off_t mc_lseek (int fd, off_t offset, int whence); 
  • src/filemanager/file.c

    diff --git a/src/filemanager/file.c b/src/filemanager/file.c
    index 0bacc54..aa6780f 100644
    a b warn_same_file (const char *fmt, const char *a, const char *b) 
    663663} 
    664664 
    665665/* --------------------------------------------------------------------------------------------- */ 
     666 
     667static void 
     668get_times( const struct stat *sb, timesbuf_st *times) 
     669{ 
     670#ifdef HAVE_UTIMENSAT 
     671    (*times)[0] = sb->st_atim; 
     672    (*times)[1] = sb->st_mtim; 
     673#else 
     674    times->actime  = sb->st_atime; 
     675    times->modtime = sb->st_mtime; 
     676#endif 
     677} 
     678 
     679/* --------------------------------------------------------------------------------------------- */ 
    666680/* {{{ Query/status report routines */ 
    667681 
    668682static FileProgressStatus 
    copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, 
    14871501    int n_read, n_written; 
    14881502    mode_t src_mode = 0;        /* The mode of the source file */ 
    14891503    struct stat sb, sb2; 
    1490     struct utimbuf utb; 
     1504    timesbuf_st times; 
    14911505    gboolean dst_exists = FALSE, appending = FALSE; 
    14921506    off_t file_size = -1; 
    14931507    FileProgressStatus return_status, temp_status; 
    copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, 
    16811695    src_mode = sb.st_mode; 
    16821696    src_uid = sb.st_uid; 
    16831697    src_gid = sb.st_gid; 
    1684     utb.actime = sb.st_atime; 
    1685     utb.modtime = sb.st_mtime; 
     1698    get_times(&sb, &times); 
    16861699    file_size = sb.st_size; 
    16871700 
    16881701    open_flags = O_WRONLY; 
    copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx, 
    19922005                src_mode = 0100666 & ~src_mode; 
    19932006                mc_chmod (dst_vpath, (src_mode & ctx->umask_kill)); 
    19942007            } 
    1995             mc_utime (dst_vpath, &utb); 
     2008            mc_utime (dst_vpath, &times); 
    19962009        } 
    19972010    } 
    19982011 
    copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const cha 
    22542267 
    22552268    if (ctx->preserve) 
    22562269    { 
    2257         struct utimbuf utb; 
     2270        timesbuf_st times; 
    22582271 
    22592272        mc_chmod (dst_vpath, cbuf.st_mode & ctx->umask_kill); 
    2260         utb.actime = cbuf.st_atime; 
    2261         utb.modtime = cbuf.st_mtime; 
    2262         mc_utime (dst_vpath, &utb); 
     2273        get_times(&cbuf, &times); 
     2274        mc_utime (dst_vpath, &times); 
    22632275    } 
    22642276    else 
    22652277    { 
  • src/vfs/fish/fish.c

    diff --git a/src/vfs/fish/fish.c b/src/vfs/fish/fish.c
    index 1172f31..35ec623 100644
    a b fish_chown (const vfs_path_t * vpath, uid_t owner, gid_t group) 
    13201320 
    13211321/* --------------------------------------------------------------------------------------------- */ 
    13221322 
     1323static time_t 
     1324get_atime(const timesbuf_st *times) 
     1325{ 
     1326    time_t ret; 
     1327 
     1328#ifdef HAVE_UTIMENSAT 
     1329    ret = (*times)[0].tv_sec; 
     1330#else 
     1331    ret = times->actime; 
     1332#endif 
     1333    return ret; 
     1334} 
     1335 
     1336/* --------------------------------------------------------------------------------------------- */ 
     1337 
     1338static time_t 
     1339get_mtime(const timesbuf_st *times) 
     1340{ 
     1341    time_t ret; 
     1342 
     1343#ifdef HAVE_UTIMENSAT 
     1344    ret = (*times)[1].tv_sec; 
     1345#else 
     1346    ret = times->modtime; 
     1347#endif 
     1348    return ret; 
     1349} 
     1350 
     1351/* --------------------------------------------------------------------------------------------- */ 
     1352 
    13231353static int 
    1324 fish_utime (const vfs_path_t * vpath, struct utimbuf *times) 
     1354fish_utime (const vfs_path_t *vpath, const timesbuf_st *times) 
    13251355{ 
    13261356    gchar *shell_commands = NULL; 
    1327     char utcmtime[16], utcatime[16]; 
     1357    char utcatime[16], utcmtime[16]; 
     1358    time_t atime, mtime; 
    13281359    struct tm *gmt; 
    13291360 
    13301361    char buf[BUF_LARGE]; 
    fish_utime (const vfs_path_t * vpath, struct utimbuf *times) 
    13401371        return -1; 
    13411372    rpath = strutils_shell_escape (crpath); 
    13421373 
    1343     gmt = gmtime (&times->modtime); 
    1344     g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d", 
     1374    atime = get_atime(times); 
     1375    gmt = gmtime(&atime); 
     1376    g_snprintf (utcatime, sizeof (utcatime), "%04d%02d%02d%02d%02d.%02d", 
    13451377                gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, 
    13461378                gmt->tm_hour, gmt->tm_min, gmt->tm_sec); 
    13471379 
    1348     gmt = gmtime (&times->actime); 
    1349     g_snprintf (utcatime, sizeof (utcatime), "%04d%02d%02d%02d%02d.%02d", 
     1380    mtime = get_mtime(times); 
     1381    gmt = gmtime(&mtime); 
     1382    g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d", 
    13501383                gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, 
    13511384                gmt->tm_hour, gmt->tm_min, gmt->tm_sec); 
    13521385 
    13531386    shell_commands = 
    13541387        g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILEATIME=%ld FISH_FILEMTIME=%ld ", 
    13551388                     "FISH_TOUCHATIME=%s FISH_TOUCHMTIME=%s;\n", SUP->scr_utime, (char *) NULL); 
    1356     g_snprintf (buf, sizeof (buf), shell_commands, rpath, (long) times->actime, 
    1357                 (long) times->modtime, utcatime, utcmtime); 
     1389    g_snprintf (buf, sizeof (buf), shell_commands, rpath, (long) atime, (long) mtime, 
     1390                utcatime, utcmtime); 
    13581391    g_free (shell_commands); 
    13591392    g_free (rpath); 
    13601393    return fish_send_command (path_element->class, super, buf, OPT_FLUSH); 
  • src/vfs/local/local.c

    diff --git a/src/vfs/local/local.c b/src/vfs/local/local.c
    index 7ea70f2..75ed258 100644
    a b local_chown (const vfs_path_t * vpath, uid_t owner, gid_t group) 
    169169/* --------------------------------------------------------------------------------------------- */ 
    170170 
    171171static int 
    172 local_utime (const vfs_path_t * vpath, struct utimbuf *times) 
     172local_utime (const vfs_path_t * vpath, const timesbuf_st *times) 
    173173{ 
     174    int ret; 
    174175    const vfs_path_element_t *path_element; 
    175176 
    176177    path_element = vfs_path_get_by_index (vpath, -1); 
    177     return utime (path_element->path, times); 
     178#ifdef HAVE_UTIMENSAT 
     179    ret = utimensat (AT_FDCWD, path_element->path, *times, 0); 
     180#else 
     181    ret = utime (path_element->path, times); 
     182#endif 
     183    return ret; 
    178184} 
    179185 
    180186/* --------------------------------------------------------------------------------------------- */ 
  • src/vfs/sfs/sfs.c

    diff --git a/src/vfs/sfs/sfs.c b/src/vfs/sfs/sfs.c
    index 90b36ec..d6f554c 100644
    a b sfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group) 
    319319/* --------------------------------------------------------------------------------------------- */ 
    320320 
    321321static int 
    322 sfs_utime (const vfs_path_t * vpath, struct utimbuf *times) 
     322sfs_utime (const vfs_path_t * vpath, const timesbuf_st *times) 
    323323{ 
    324     return utime (sfs_redirect (vpath), times); 
     324    int ret; 
     325 
     326#ifdef HAVE_UTIMENSAT 
     327    ret = utimensat (AT_FDCWD, sfs_redirect (vpath), *times, 0); 
     328#else 
     329    ret = utime (sfs_redirect (vpath), times); 
     330#endif 
     331    return ret; 
    325332} 
    326333 
    327334/* --------------------------------------------------------------------------------------------- */ 
  • src/vfs/sftpfs/vfs_class.c

    diff --git a/src/vfs/sftpfs/vfs_class.c b/src/vfs/sftpfs/vfs_class.c
    index 3504c26..d542cdd 100644
    a b sftpfs_cb_readlink (const vfs_path_t * vpath, char *buf, size_t size) 
    330330 */ 
    331331 
    332332static int 
    333 sftpfs_cb_utime (const vfs_path_t * vpath, struct utimbuf *times) 
     333sftpfs_cb_utime (const vfs_path_t * vpath, const timesbuf_st *times) 
    334334{ 
    335335    (void) vpath; 
    336336    (void) times; 
  • src/vfs/smbfs/smbfs.c

    diff --git a/src/vfs/smbfs/smbfs.c b/src/vfs/smbfs/smbfs.c
    index cf507e6..bf1874f 100644
    a b smbfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group) 
    995995/* --------------------------------------------------------------------------------------------- */ 
    996996 
    997997static int 
    998 smbfs_utime (const vfs_path_t * vpath, struct utimbuf *times) 
     998smbfs_utime (const vfs_path_t * vpath, const timesbuf_st *times) 
    999999{ 
    10001000    const vfs_path_element_t *path_element; 
    10011001 
    10021002    (void) times; 
    10031003 
    10041004    path_element = vfs_path_get_by_index (vpath, -1); 
     1005#ifdef HAVE_UTIMENSAT 
     1006    DEBUG (3, ("smbfs_utimensat(path:%s)\n", path_element->path)); 
     1007#else 
    10051008    DEBUG (3, ("smbfs_utime(path:%s)\n", path_element->path)); 
     1009#endif 
    10061010    my_errno = EOPNOTSUPP; 
    10071011    return -1; 
    10081012}