mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 12:32:40 +03:00
Merge branch '3575_nanoseconds'
* 3575_nanoseconds: FISH VFS: generate timestamps with nanosecond precision for touch. (fish_utime): avoid buffer overflow: allocate buffer for command dynamically. Ticket #3575: preserve timestamps with nanosecond precisions during file copy
This commit is contained in:
commit
4a6fb3b534
@ -229,6 +229,9 @@ AC_CHECK_FUNCS([\
|
||||
realpath
|
||||
])
|
||||
|
||||
dnl utimensat is supported since glibc 2.6 and specified in POSIX.1-2008
|
||||
AC_CHECK_FUNCS([utimensat])
|
||||
|
||||
dnl getpt is a GNU Extension (glibc 2.1.x)
|
||||
AC_CHECK_FUNCS(posix_openpt, , [AC_CHECK_FUNCS(getpt)])
|
||||
AC_CHECK_FUNCS(grantpt, , [AC_CHECK_LIB(pt, grantpt)])
|
||||
|
@ -251,7 +251,7 @@ int mc_##name inarg \
|
||||
|
||||
MC_NAMEOP (chmod, (const vfs_path_t *vpath, mode_t mode), (vpath, mode))
|
||||
MC_NAMEOP (chown, (const vfs_path_t *vpath, uid_t owner, gid_t group), (vpath, owner, group))
|
||||
MC_NAMEOP (utime, (const vfs_path_t *vpath, struct utimbuf * times), (vpath, times))
|
||||
MC_NAMEOP (utime, (const vfs_path_t *vpath, mc_timesbuf_t * times), (vpath, times))
|
||||
MC_NAMEOP (readlink, (const vfs_path_t *vpath, char *buf, size_t bufsiz), (vpath, buf, bufsiz))
|
||||
MC_NAMEOP (unlink, (const vfs_path_t *vpath), (vpath))
|
||||
MC_NAMEOP (mkdir, (const vfs_path_t *vpath, mode_t mode), (vpath, mode))
|
||||
|
@ -10,7 +10,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#ifdef HAVE_UTIME_H
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
#include <sys/time.h>
|
||||
#elif defined (HAVE_UTIME_H)
|
||||
#include <utime.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
@ -97,6 +99,12 @@ typedef void (*fill_names_f) (const char *);
|
||||
|
||||
typedef void *vfsid;
|
||||
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
typedef struct timespec mc_timesbuf_t[2];
|
||||
#else
|
||||
typedef struct utimbuf mc_timesbuf_t;
|
||||
#endif
|
||||
|
||||
/*** enums ***************************************************************************************/
|
||||
|
||||
/* Flags of VFS classes */
|
||||
@ -167,7 +175,7 @@ typedef struct vfs_class
|
||||
|
||||
int (*chmod) (const vfs_path_t * vpath, mode_t mode);
|
||||
int (*chown) (const vfs_path_t * vpath, uid_t owner, gid_t group);
|
||||
int (*utime) (const vfs_path_t * vpath, struct utimbuf * times);
|
||||
int (*utime) (const vfs_path_t * vpath, mc_timesbuf_t * times);
|
||||
|
||||
int (*readlink) (const vfs_path_t * vpath, char *buf, size_t size);
|
||||
int (*symlink) (const vfs_path_t * vpath1, const vfs_path_t * vpath2);
|
||||
@ -279,7 +287,7 @@ int vfs_preallocate (int dest_desc, off_t src_fsize, off_t dest_fsize);
|
||||
*/
|
||||
ssize_t mc_read (int handle, void *buffer, size_t count);
|
||||
ssize_t mc_write (int handle, const void *buffer, size_t count);
|
||||
int mc_utime (const vfs_path_t * vpath, struct utimbuf *times);
|
||||
int mc_utime (const vfs_path_t * vpath, mc_timesbuf_t * times);
|
||||
int mc_readlink (const vfs_path_t * vpath, char *buf, size_t bufsiz);
|
||||
int mc_close (int handle);
|
||||
off_t mc_lseek (int fd, off_t offset, int whence);
|
||||
|
@ -659,6 +659,20 @@ warn_same_file (const char *fmt, const char *a, const char *b)
|
||||
return real_warn_same_file (Foreground, fmt, a, b);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
get_times (const struct stat *sb, mc_timesbuf_t * times)
|
||||
{
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
(*times)[0] = sb->st_atim;
|
||||
(*times)[1] = sb->st_mtim;
|
||||
#else
|
||||
times->actime = sb->st_atime;
|
||||
times->modtime = sb->st_mtime;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/* {{{ Query/status report routines */
|
||||
|
||||
@ -1484,7 +1498,7 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx,
|
||||
int src_desc, dest_desc = -1;
|
||||
mode_t src_mode = 0; /* The mode of the source file */
|
||||
struct stat src_stat, dst_stat;
|
||||
struct utimbuf utb;
|
||||
mc_timesbuf_t times;
|
||||
gboolean dst_exists = FALSE, appending = FALSE;
|
||||
off_t file_size = -1;
|
||||
FileProgressStatus return_status, temp_status;
|
||||
@ -1679,8 +1693,7 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx,
|
||||
src_mode = src_stat.st_mode;
|
||||
src_uid = src_stat.st_uid;
|
||||
src_gid = src_stat.st_gid;
|
||||
utb.actime = src_stat.st_atime;
|
||||
utb.modtime = src_stat.st_mtime;
|
||||
get_times (&src_stat, ×);
|
||||
file_size = src_stat.st_size;
|
||||
|
||||
open_flags = O_WRONLY;
|
||||
@ -1995,7 +2008,7 @@ copy_file_file (file_op_total_context_t * tctx, file_op_context_t * ctx,
|
||||
src_mode = 0100666 & ~src_mode;
|
||||
mc_chmod (dst_vpath, (src_mode & ctx->umask_kill));
|
||||
}
|
||||
mc_utime (dst_vpath, &utb);
|
||||
mc_utime (dst_vpath, ×);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2257,12 +2270,11 @@ copy_dir_dir (file_op_total_context_t * tctx, file_op_context_t * ctx, const cha
|
||||
|
||||
if (ctx->preserve)
|
||||
{
|
||||
struct utimbuf utb;
|
||||
mc_timesbuf_t times;
|
||||
|
||||
mc_chmod (dst_vpath, cbuf.st_mode & ctx->umask_kill);
|
||||
utb.actime = cbuf.st_atime;
|
||||
utb.modtime = cbuf.st_mtime;
|
||||
mc_utime (dst_vpath, &utb);
|
||||
get_times (&cbuf, ×);
|
||||
mc_utime (dst_vpath, ×);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1323,17 +1323,49 @@ fish_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fish_get_atime (mc_timesbuf_t * times, time_t * sec, long *nsec)
|
||||
{
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
*sec = (*times)[0].tv_sec;
|
||||
*nsec = (*times)[0].tv_nsec;
|
||||
#else
|
||||
*sec = times->actime;
|
||||
*nsec = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fish_get_mtime (mc_timesbuf_t * times, time_t * sec, long *nsec)
|
||||
{
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
*sec = (*times)[1].tv_sec;
|
||||
*nsec = (*times)[1].tv_nsec;
|
||||
#else
|
||||
*sec = times->modtime;
|
||||
*nsec = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
fish_utime (const vfs_path_t * vpath, struct utimbuf *times)
|
||||
fish_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
|
||||
{
|
||||
gchar *shell_commands = NULL;
|
||||
char utcmtime[16], utcatime[16];
|
||||
char utcatime[16], utcmtime[16];
|
||||
char utcatime_w_nsec[30], utcmtime_w_nsec[30];
|
||||
time_t atime, mtime;
|
||||
long atime_nsec, mtime_nsec;
|
||||
struct tm *gmt;
|
||||
char buf[BUF_LARGE];
|
||||
char *cmd;
|
||||
const char *crpath;
|
||||
char *rpath;
|
||||
struct vfs_s_super *super;
|
||||
const vfs_path_element_t *path_element;
|
||||
int ret;
|
||||
|
||||
path_element = vfs_path_get_by_index (vpath, -1);
|
||||
|
||||
@ -1342,24 +1374,38 @@ fish_utime (const vfs_path_t * vpath, struct utimbuf *times)
|
||||
return -1;
|
||||
rpath = strutils_shell_escape (crpath);
|
||||
|
||||
gmt = gmtime (×->modtime);
|
||||
g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d",
|
||||
gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
|
||||
gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
|
||||
|
||||
gmt = gmtime (×->actime);
|
||||
fish_get_atime (times, &atime, &atime_nsec);
|
||||
gmt = gmtime (&atime);
|
||||
g_snprintf (utcatime, sizeof (utcatime), "%04d%02d%02d%02d%02d.%02d",
|
||||
gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
|
||||
gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
|
||||
g_snprintf (utcatime_w_nsec, sizeof (utcatime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
|
||||
gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
|
||||
gmt->tm_hour, gmt->tm_min, gmt->tm_sec, atime_nsec);
|
||||
|
||||
fish_get_mtime (times, &mtime, &mtime_nsec);
|
||||
gmt = gmtime (&mtime);
|
||||
g_snprintf (utcmtime, sizeof (utcmtime), "%04d%02d%02d%02d%02d.%02d",
|
||||
gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
|
||||
gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
|
||||
g_snprintf (utcmtime_w_nsec, sizeof (utcmtime_w_nsec), "%04d-%02d-%02d %02d:%02d:%02d.%09ld",
|
||||
gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
|
||||
gmt->tm_hour, gmt->tm_min, gmt->tm_sec, mtime_nsec);
|
||||
|
||||
shell_commands =
|
||||
g_strconcat (SUP->scr_env, "FISH_FILENAME=%s FISH_FILEATIME=%ld FISH_FILEMTIME=%ld ",
|
||||
"FISH_TOUCHATIME=%s FISH_TOUCHMTIME=%s;\n", SUP->scr_utime, (char *) NULL);
|
||||
g_snprintf (buf, sizeof (buf), shell_commands, rpath, (long) times->actime,
|
||||
(long) times->modtime, utcatime, utcmtime);
|
||||
"FISH_TOUCHATIME=%s FISH_TOUCHMTIME=%s ",
|
||||
"FISH_TOUCHATIME_W_NSEC=\"%s\" FISH_TOUCHMTIME_W_NSEC=\"%s\";\n",
|
||||
SUP->scr_utime, (char *) NULL);
|
||||
cmd =
|
||||
g_strdup_printf (shell_commands, rpath, (long) atime, (long) mtime, utcatime, utcmtime,
|
||||
utcatime_w_nsec, utcmtime_w_nsec);
|
||||
g_free (shell_commands);
|
||||
g_free (rpath);
|
||||
return fish_send_command (path_element->class, super, buf, OPT_FLUSH);
|
||||
ret = fish_send_command (path_element->class, super, cmd, OPT_FLUSH);
|
||||
g_free (cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -76,17 +76,21 @@
|
||||
|
||||
/* default 'utime' script */
|
||||
#define FISH_UTIME_DEF_CONTENT "" \
|
||||
"#UTIME $FISH_FILEATIME $FISH_FILEMTIME $FISH_FILENAME\n" \
|
||||
"if [ -n \"$FISH_HAVE_PERL\" ] && \\\n" \
|
||||
" perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \
|
||||
"#UTIME \"$FISH_TOUCHATIME_W_NSEC\" \"$FISH_TOUCHMTIME_W_NSEC\" $FISH_FILENAME\n" \
|
||||
"if TZ=UTC touch -m -d \"$FISH_TOUCHMTIME_W_NSEC\" \"/${FISH_FILENAME}\" 2>/dev/null && \\\n" \
|
||||
" TZ=UTC touch -a -d \"$FISH_TOUCHATIME_W_NSEC\" \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \
|
||||
" echo \"### 000\"\n" \
|
||||
"elif TZ=UTC touch -m -t $FISH_TOUCHMTIME \"/${FISH_FILENAME}\" 2>/dev/null && \\\n" \
|
||||
" TZ=UTC touch -a -t $FISH_TOUCHATIME \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \
|
||||
" echo \"### 000\"\n" \
|
||||
"elif [ -n \"$FISH_HAVE_PERL\" ] && \\\n" \
|
||||
" perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' \"/${FISH_FILENAME}\" 2>/dev/null; then\n" \
|
||||
" echo \"### 000\"\n" \
|
||||
"else\n" \
|
||||
" echo \"### 500\"\n" \
|
||||
"fi\n"
|
||||
|
||||
|
||||
/* default 'rmdir' script */
|
||||
#define FISH_RMDIR_DEF_CONTENT "" \
|
||||
"#RMD $FISH_FILENAME\n" \
|
||||
|
@ -1,10 +1,13 @@
|
||||
#UTIME $FISH_FILEATIME $FISH_FILEMTIME $FISH_FILENAME
|
||||
if [ -n "$FISH_HAVE_PERL" ] &&
|
||||
perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' "/${FISH_FILENAME}" 2>/dev/null; then
|
||||
#UTIME "$FISH_TOUCHATIME_W_NSEC" "$FISH_TOUCHMTIME_W_NSEC" "$FISH_FILENAME"
|
||||
if TZ=UTC touch -m -d "$FISH_TOUCHMTIME_W_NSEC" "/${FISH_FILENAME}" 2>/dev/null && \
|
||||
TZ=UTC touch -a -d "$FISH_TOUCHATIME_W_NSEC" "/${FISH_FILENAME}" 2>/dev/null; then
|
||||
echo "### 000"
|
||||
elif TZ=UTC touch -m -t $FISH_TOUCHMTIME "/${FISH_FILENAME}" 2>/dev/null &&
|
||||
elif TZ=UTC touch -m -t $FISH_TOUCHMTIME "/${FISH_FILENAME}" 2>/dev/null && \
|
||||
TZ=UTC touch -a -t $FISH_TOUCHATIME "/${FISH_FILENAME}" 2>/dev/null; then
|
||||
echo "### 000"
|
||||
elif [ -n "$FISH_HAVE_PERL" ] &&
|
||||
perl -e 'utime '$FISH_FILEATIME','$FISH_FILEMTIME',@ARGV;' "/${FISH_FILENAME}" 2>/dev/null; then
|
||||
echo "### 000"
|
||||
else
|
||||
echo "### 500"
|
||||
fi
|
||||
|
@ -169,12 +169,18 @@ local_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
local_utime (const vfs_path_t * vpath, struct utimbuf *times)
|
||||
local_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
|
||||
{
|
||||
int ret;
|
||||
const vfs_path_element_t *path_element;
|
||||
|
||||
path_element = vfs_path_get_by_index (vpath, -1);
|
||||
return utime (path_element->path, times);
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
ret = utimensat (AT_FDCWD, path_element->path, *times, 0);
|
||||
#else
|
||||
ret = utime (path_element->path, times);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -319,9 +319,16 @@ sfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
sfs_utime (const vfs_path_t * vpath, struct utimbuf *times)
|
||||
sfs_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
|
||||
{
|
||||
return utime (sfs_redirect (vpath), times);
|
||||
int ret;
|
||||
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
ret = utimensat (AT_FDCWD, sfs_redirect (vpath), *times, 0);
|
||||
#else
|
||||
ret = utime (sfs_redirect (vpath), times);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -330,7 +330,7 @@ sftpfs_cb_readlink (const vfs_path_t * vpath, char *buf, size_t size)
|
||||
*/
|
||||
|
||||
static int
|
||||
sftpfs_cb_utime (const vfs_path_t * vpath, struct utimbuf *times)
|
||||
sftpfs_cb_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
|
||||
{
|
||||
(void) vpath;
|
||||
(void) times;
|
||||
|
@ -995,14 +995,18 @@ smbfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
smbfs_utime (const vfs_path_t * vpath, struct utimbuf *times)
|
||||
smbfs_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
|
||||
{
|
||||
const vfs_path_element_t *path_element;
|
||||
|
||||
(void) times;
|
||||
|
||||
path_element = vfs_path_get_by_index (vpath, -1);
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
DEBUG (3, ("smbfs_utimensat(path:%s)\n", path_element->path));
|
||||
#else
|
||||
DEBUG (3, ("smbfs_utime(path:%s)\n", path_element->path));
|
||||
#endif
|
||||
my_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user