diff --git a/qse/configure b/qse/configure index b926dfa8..2c233d41 100755 --- a/qse/configure +++ b/qse/configure @@ -17616,7 +17616,7 @@ _ACEOF fi done -for ac_func in utime utimes +for ac_func in utime utimes futimes lutimes futimens do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/qse/configure.ac b/qse/configure.ac index 797fa5a0..603ae36b 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -147,7 +147,7 @@ AC_CHECK_FUNCS([isblank iswblank]) AC_CHECK_FUNCS([lseek64 stat64 fstat64 lstat64 ftruncate64 readdir64 dirfd]) AC_CHECK_FUNCS([lstat fchmod fsync ftruncate]) AC_CHECK_FUNCS([timegm timelocal localtime_r gettimeofday settimeofday]) -AC_CHECK_FUNCS([utime utimes]) +AC_CHECK_FUNCS([utime utimes futimes lutimes futimens]) AC_CHECK_FUNCS([sysconf prctl fdopendir setrlimit getrlimit]) AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_CHECK_FUNCS([fork vfork posix_spawn gettid nanosleep select]) diff --git a/qse/include/qse/cmn/fs.h b/qse/include/qse/cmn/fs.h index 8149e2b6..6cd1ea33 100644 --- a/qse/include/qse/cmn/fs.h +++ b/qse/include/qse/cmn/fs.h @@ -127,6 +127,11 @@ struct qse_fs_attr_t qse_uintmax_t size; qse_uintmax_t ino; qse_uintmax_t dev; + qse_uintptr_t uid; + qse_uintptr_t gid; + qse_ntime_t atime; /* last access */ + qse_ntime_t mtime; /* last modification */ + qse_ntime_t ctime; /* last status change */ }; typedef struct qse_fs_attr_t qse_fs_attr_t; diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index 14ca8954..b04ae2e4 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -248,6 +248,12 @@ /* Define to 1 if you have the `ftruncate64' function. */ #undef HAVE_FTRUNCATE64 +/* Define to 1 if you have the `futimens' function. */ +#undef HAVE_FUTIMENS + +/* Define to 1 if you have the `futimes' function. */ +#undef HAVE_FUTIMES + /* Define to 1 if you have the `getcontext' function. */ #undef HAVE_GETCONTEXT @@ -353,6 +359,9 @@ /* Define this if a modern libltdl is already installed */ #undef HAVE_LTDL +/* Define to 1 if you have the `lutimes' function. */ +#undef HAVE_LUTIMES + /* Define to 1 if you have the header file. */ #undef HAVE_MACH_O_DYLD_H diff --git a/qse/lib/cmn/fs-move.c b/qse/lib/cmn/fs-move.c index bce49f8f..46b3286a 100644 --- a/qse/lib/cmn/fs-move.c +++ b/qse/lib/cmn/fs-move.c @@ -515,7 +515,7 @@ DWORD copy_file_progress ( * -> symbolic link */ -static int copy_file_in_fs (qse_fs_t* fs, const cpfile_t* cpfile) +static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) { #if defined(_WIN32) /* ------------------------------------------------------ */ @@ -638,8 +638,48 @@ static int copy_file_in_fs (qse_fs_t* fs, const cpfile_t* cpfile) } } + if (cpfile->flags & QSE_FS_CPFILE_PRESERVE) + { + #if defined(HAVE_FUTIMENS) + struct timespec ts[2]; + #elif defined(HAVE_FUTIMES) + struct timeval tv[2]; + #endif + + if (QSE_FCHOWN (out, cpfile->src_attr.uid, cpfile->src_attr.gid) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + goto oops; + } + + #if defined(HAVE_FUTIMENS) + ts[0].tv_sec = cpfile->src_attr.atime.sec; + ts[0].tv_nsec = cpfile->src_attr.atime.nsec; + ts[1].tv_sec = cpfile->src_attr.mtime.sec; + ts[1].tv_nsec = cpfile->src_attr.mtime.nsec; + if (QSE_FUTIMENS (out, ts) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + goto oops; + } + #elif defined(HAVE_FUTIME) + tv[0].tv_sec = cpfile->src_attr.atime.sec; + tv[0].tv_usec = QSE_NSEC_TO_USEC(cpfile->src_attr.atime.nsec); + tv[1].tv_sec = cpfile->src_attr.mtime.sec; + tv[1].tv_usec = QSE_NSEC_TO_USEC(cpfile->src_attr.mtime.nsec); + if (QSE_FUTIMES (out, tv) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + goto oops; + } + #else + # error neither futimens nor futimes exist + #endif + } + QSE_CLOSE (out); QSE_CLOSE (in); + return 0; oops: @@ -650,10 +690,8 @@ static int copy_file_in_fs (qse_fs_t* fs, const cpfile_t* cpfile) #endif } - static int copy_file (qse_fs_t* fs, cpfile_t* cpfile) { - if (cpfile->src_attr.isdir) { fs->errnum = QSE_FS_ENOIMPL; /* TODO: copy a directory into a directory */ @@ -676,8 +714,8 @@ static int copy_file (qse_fs_t* fs, cpfile_t* cpfile) if (cpfile->dst_attr.isdir) { /* copy it to directory */ - fs->errnum = QSE_FS_ENOIMPL; /* TODO: copy a file into a directory */ - return -1; + //return copy_file_into_dir (fs, cpfile); + } if (!(cpfile->flags & QSE_FS_CPFILE_REPLACE)) @@ -693,7 +731,9 @@ static int copy_file (qse_fs_t* fs, cpfile_t* cpfile) return copy_file_in_fs (fs, cpfile); } - fs->errnum = QSE_FS_ENOIMPL; /* TODO: copy a file into a directory */ + + /* source is a directory. is a recursive copy allowed? */ + fs->errnum = QSE_FS_ENOIMPL; return -1; } } diff --git a/qse/lib/cmn/fs.c b/qse/lib/cmn/fs.c index af600a2a..9e69a0ba 100644 --- a/qse/lib/cmn/fs.c +++ b/qse/lib/cmn/fs.c @@ -856,6 +856,28 @@ int qse_fs_getattr (qse_fs_t* fs, const qse_fs_char_t* fspath, qse_fs_attr_t* at attr->size = st.st_size; attr->ino = st.st_ino; attr->dev = st.st_dev; + attr->uid = st.st_uid; + attr->gid = st.st_gid; + + #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + attr->atime.sec = st.st_atim.tv_sec; + attr->atime.nsec = st.st_atim.tv_nsec; + attr->mtime.sec = st.st_mtim.tv_sec; + attr->mtime.nsec = st.st_mtim.tv_nsec; + attr->ctime.sec = st.st_ctim.tv_sec; + attr->ctime.nsec = st.st_ctim.tv_nsec; + #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + attr->atime.sec = st.st_atimespec.tv_sec; + attr->atime.nsec = st.st_atimespec.tv_nsec; + attr->mtime.sec = st.st_mtimespec.tv_sec; + attr->mtime.nsec = st.st_mtimespec.tv_nsec; + attr->ctime.sec = st.st_ctimespec.tv_sec; + attr->ctime.nsec = st.st_ctimespec.tv_nsec; + #else + attr->atime.sec = st.st_atime; + attr->mtime.sec = st.st_mtime; + attr->ctime.sec = st.st_ctime; + #endif return 0; #endif } diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h index 0199e674..77e52bec 100644 --- a/qse/lib/cmn/syscall.h +++ b/qse/lib/cmn/syscall.h @@ -392,6 +392,24 @@ # define QSE_UTIMES(path,t) utimes(path,t) #endif +#if defined(SYS_futimes) && defined(QSE_USE_SYSCALL) +# define QSE_FUTIMES(fd,t) syscall(SYS_futimes,fd,t) +#else +# define QSE_FUTIMES(fd,t) futimes(fd,t) +#endif + +#if defined(SYS_lutimes) && defined(QSE_USE_SYSCALL) +# define QSE_LUTIMES(fd,t) syscall(SYS_lutimes,fd,t) +#else +# define QSE_LUTIMES(fd,t) lutimes(fd,t) +#endif + +#if defined(SYS_futimens) && defined(QSE_USE_SYSCALL) +# define QSE_FUTIMENS(fd,t) syscall(SYS_futimens,fd,t) +#else +# define QSE_FUTIMENS(fd,t) futimens(fd,t) +#endif + /* ===== DIRECTORY - not really system calls ===== */ #define QSE_OPENDIR(name) opendir(name) #define QSE_CLOSEDIR(dir) closedir(dir)