Feature #7106 » 0001-Add-support-for-lutimes-3-to-file.c-as-File-lutime.patch
| configure.in | ||
|---|---|---|
| 
       AC_LIBOBJ([signbit]) 
   | 
||
| 
     fi 
   | 
||
| 
     AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot getcwd eaccess\ 
   | 
||
| 
     	      truncate ftruncate ftello chsize times utimes utimensat fcntl lockf lstat\ 
   | 
||
| 
     	      truncate ftruncate ftello chsize times utimes lutimes utimensat fcntl lockf lstat\ 
   | 
||
| 
     	      truncate64 ftruncate64 ftello64 fseeko fseeko64 \ 
   | 
||
| 
     	      link symlink readlink readdir_r fsync fdatasync fchown posix_fadvise\ 
   | 
||
| 
     	      setitimer setruid seteuid setreuid setresuid socketpair\ 
   | 
||
| file.c | ||
|---|---|---|
| 
     #define rb_file_s_lchown rb_f_notimplement 
   | 
||
| 
     #endif 
   | 
||
| 
     typedef enum utime_mode utime_mode_t; 
   | 
||
| 
     enum utime_mode { 
   | 
||
| 
         M_SYMLINK_FOLLOW = 0, 
   | 
||
| 
         M_SYMLINK_NOFOLLOW 
   | 
||
| 
     }; 
   | 
||
| 
     struct utime_args { 
   | 
||
| 
         const struct timespec* tsp; 
   | 
||
| 
         VALUE atime, mtime; 
   | 
||
| 
         utime_mode_t mode; 
   | 
||
| 
     }; 
   | 
||
| 
     #if !defined(FOLLOW_SYMLINK_P) 
   | 
||
| 
     # define FOLLOW_SYMLINK_P(x) ((x)->mode == M_SYMLINK_FOLLOW) 
   | 
||
| 
     #endif 
   | 
||
| 
     #if defined DOSISH || defined __CYGWIN__ 
   | 
||
| 
     NORETURN(static void utime_failed(VALUE, const struct timespec *, VALUE, VALUE)); 
   | 
||
| ... | ... | |
| 
     #if defined(HAVE_UTIMES) 
   | 
||
| 
     static void 
   | 
||
| 
     utime_internal(const char *path, VALUE pathv, void *arg) 
   | 
||
| 
     utime_helper(const char *path, VALUE pathv, void *arg) 
   | 
||
| 
     { 
   | 
||
| 
         struct utime_args *v = arg; 
   | 
||
| 
         const struct timespec *tsp = v->tsp; 
   | 
||
| ... | ... | |
| 
     #ifdef HAVE_UTIMENSAT 
   | 
||
| 
         static int try_utimensat = 1; 
   | 
||
| 
         const int flags = FOLLOW_SYMLINK_P(v) ? 0 : AT_SYMLINK_NOFOLLOW; 
   | 
||
| 
         if (try_utimensat) { 
   | 
||
| 
             if (utimensat(AT_FDCWD, path, tsp, 0) < 0) { 
   | 
||
| 
             if (utimensat(AT_FDCWD, path, tsp, flags) < 0) { 
   | 
||
| 
                 if (errno == ENOSYS) { 
   | 
||
| 
                     try_utimensat = 0; 
   | 
||
| 
                     goto no_utimensat; 
   | 
||
| ... | ... | |
| 
             tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000); 
   | 
||
| 
             tvp = tvbuf; 
   | 
||
| 
         } 
   | 
||
| 
         if (utimes(path, tvp) < 0) 
   | 
||
| 
         if ((FOLLOW_SYMLINK_P(v) ? utimes(path, tvp) : lutimes(path, tvp)) < 0) 
   | 
||
| 
     	utime_failed(pathv, tsp, v->atime, v->mtime); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     #endif 
   | 
||
| 
     static void 
   | 
||
| 
     utime_internal(const char *path, VALUE pathv, void *arg) 
   | 
||
| 
     utime_helper(const char *path, VALUE pathv, void *arg) 
   | 
||
| 
     { 
   | 
||
| 
         struct utime_args *v = arg; 
   | 
||
| 
         const struct timespec *tsp = v->tsp; 
   | 
||
| ... | ... | |
| 
             utbuf.modtime = tsp[1].tv_sec; 
   | 
||
| 
             utp = &utbuf; 
   | 
||
| 
         } 
   | 
||
| 
         if (utime(path, utp) < 0) 
   | 
||
| 
         if ((FOLLOW_SYMLINK_P(v) ? utimes(path, utp) : lutimes(path, utp)) < 0) 
   | 
||
| 
     	utime_failed(pathv, tsp, v->atime, v->mtime); 
   | 
||
| 
     } 
   | 
||
| 
     #endif 
   | 
||
| 
     /* 
   | 
||
| 
      * call-seq: 
   | 
||
| 
      *  File.utime(atime, mtime, file_name,...)   ->  integer 
   | 
||
| 
      * 
   | 
||
| 
      * Sets the access and modification times of each 
   | 
||
| 
      * named file to the first two arguments. Returns 
   | 
||
| 
      * the number of file names in the argument list. 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     rb_file_s_utime(int argc, VALUE *argv) 
   | 
||
| 
     utime_internal(int argc, VALUE *argv, utime_mode_t mode) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE rest; 
   | 
||
| 
         struct utime_args args; 
   | 
||
| ... | ... | |
| 
     	tsp[1] = rb_time_timespec(args.mtime); 
   | 
||
| 
         } 
   | 
||
| 
         args.tsp = tsp; 
   | 
||
| 
     #ifdef HAVE_LUTIMES 
   | 
||
| 
         args.mode = mode; 
   | 
||
| 
     #else 
   | 
||
| 
         args.mode = M_SYMLINK_FOLLOW; 
   | 
||
| 
     #endif 
   | 
||
| 
         n = apply2files(utime_internal, rest, &args); 
   | 
||
| 
         n = apply2files(utime_helper, rest, &args); 
   | 
||
| 
         return LONG2FIX(n); 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      * call-seq: 
   | 
||
| 
      *  File.utime(atime, mtime, file_name,...)   ->  integer 
   | 
||
| 
      * 
   | 
||
| 
      * Sets the access and modification times of each 
   | 
||
| 
      * named file to the first two arguments. Returns 
   | 
||
| 
      * the number of file names in the argument list. 
   | 
||
| 
      * See also File::lutime. 
   | 
||
| 
      */ 
   | 
||
| 
     static inline VALUE 
   | 
||
| 
     rb_file_s_utime(int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         return utime_internal(argc, argv, M_SYMLINK_FOLLOW); 
   | 
||
| 
     } 
   | 
||
| 
     #ifdef HAVE_LUTIMES 
   | 
||
| 
     /* 
   | 
||
| 
      * call-seq: 
   | 
||
| 
      *  File.lutime(atime, mtime, file_name,...)   ->  integer 
   | 
||
| 
      * 
   | 
||
| 
      * Equivalent to File::utime, but does not follow 
   | 
||
| 
      * symbolic links (so it will change the +atime+ 
   | 
||
| 
      * and +mtime+ associated with the link, not the 
   | 
||
| 
      * file referenced by the link). Often not available. 
   | 
||
| 
      * 
   | 
||
| 
      * See also File::utime. 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     rb_file_s_lutime(int argc, VALUE *argv) 
   | 
||
| 
     { 
   | 
||
| 
         return utime_internal(argc, argv, M_SYMLINK_NOFOLLOW); 
   | 
||
| 
     } 
   | 
||
| 
     #else 
   | 
||
| 
     #define rb_file_s_lutime rb_f_notimplement 
   | 
||
| 
     #endif 
   | 
||
| 
     #if defined(FOLLOW_SYMLINK_P) 
   | 
||
| 
     # undef FOLLOW_SYMLINK_P 
   | 
||
| 
     #endif 
   | 
||
| 
     NORETURN(static void sys_fail2(VALUE,VALUE)); 
   | 
||
| 
     static void 
   | 
||
| 
     sys_fail2(VALUE s1, VALUE s2) 
   | 
||
| ... | ... | |
| 
         rb_define_singleton_method(rb_cFile, "ctime", rb_file_s_ctime, 1); 
   | 
||
| 
         rb_define_singleton_method(rb_cFile, "utime", rb_file_s_utime, -1); 
   | 
||
| 
         rb_define_singleton_method(rb_cFile, "lutime", rb_file_s_lutime, -1); 
   | 
||
| 
         rb_define_singleton_method(rb_cFile, "chmod", rb_file_s_chmod, -1); 
   | 
||
| 
         rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1); 
   | 
||
| 
         rb_define_singleton_method(rb_cFile, "lchmod", rb_file_s_lchmod, -1); 
   | 
||
| test/ruby/test_file_exhaustive.rb | ||
|---|---|---|
| 
         assert_equal(t + 2, File.mtime(@zerofile)) 
   | 
||
| 
       end 
   | 
||
| 
       def test_lutime 
   | 
||
| 
         return unless @symlinkfile 
   | 
||
| 
         t = Time.local(2000) 
   | 
||
| 
         assert_equal(1, File.lutime(t + 1, t + 2, @symlinkfile)) 
   | 
||
| 
         assert_equal(2, File.lutime(t + 1, t + 2, @symlinkfile, @symlinkfile)) 
   | 
||
| 
         assert_equal(t + 1, File.lstat(@symlinkfile).atime) 
   | 
||
| 
         assert_equal(t + 2, File.lstat(@symlinkfile).mtime) 
   | 
||
| 
         assert_not_equal(t + 1, File.atime(@symlinkfile)) 
   | 
||
| 
         assert_not_equal(t + 2, File.mtime(@symlinkfile)) 
   | 
||
| 
         assert_raise(Errno::ENOENT) { File.lutime(t + 1, t + 2, @nofile) } 
   | 
||
| 
       rescue NotImplementedError 
   | 
||
| 
       end 
   | 
||
| 
       def test_hardlink 
   | 
||
| 
         return unless @hardlinkfile 
   | 
||
| 
         assert_equal("file", File.ftype(@hardlinkfile)) 
   | 
||