[前][次][番号順一覧][スレッド一覧]

ruby-changes:48816

From: nobu <ko1@a...>
Date: Wed, 29 Nov 2017 18:59:27 +0900 (JST)
Subject: [ruby-changes:48816] nobu:r60933 (trunk): file.c: File.lutime

nobu	2017-11-29 18:59:20 +0900 (Wed, 29 Nov 2017)

  New Revision: 60933

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60933

  Log:
    file.c: File.lutime
    
    * file.c (utime_internal): add File.lutime.  [Feature #4052]

  Modified files:
    trunk/NEWS
    trunk/configure.ac
    trunk/file.c
    trunk/test/ruby/test_file_exhaustive.rb
Index: configure.ac
===================================================================
--- configure.ac	(revision 60932)
+++ configure.ac	(revision 60933)
@@ -2328,6 +2328,7 @@ AC_CHECK_FUNCS(llabs) https://github.com/ruby/ruby/blob/trunk/configure.ac#L2328
 AC_CHECK_FUNCS(lockf)
 AC_CHECK_FUNCS(log2)
 AC_CHECK_FUNCS(lstat)
+AC_CHECK_FUNCS(lutime)
 AC_CHECK_FUNCS(malloc_usable_size)
 AC_CHECK_FUNCS(malloc_size)
 AC_CHECK_FUNCS(mblen)
Index: NEWS
===================================================================
--- NEWS	(revision 60932)
+++ NEWS	(revision 60933)
@@ -46,6 +46,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L46
   * File.stat, File.exist?, and other rb_stat()-using methods release GVL
     [Bug #13941]
   * File.rename releases GVL [Feature #13951]
+  * Add File.lutime  [Feature #4052]
 
 * Hash
 
Index: test/ruby/test_file_exhaustive.rb
===================================================================
--- test/ruby/test_file_exhaustive.rb	(revision 60932)
+++ test/ruby/test_file_exhaustive.rb	(revision 60933)
@@ -647,6 +647,36 @@ class TestFileExhaustive < Test::Unit::T https://github.com/ruby/ruby/blob/trunk/test/ruby/test_file_exhaustive.rb#L647
     assert_equal(t + 2, File.mtime(zerofile))
   end
 
+  def test_utime_symlinkfile
+    return unless symlinkfile
+    t = Time.local(2000)
+    stat = File.lstat(symlinkfile)
+    assert_equal(File.utime(t, t, symlinkfile), 1)
+    assert_equal(File.stat(regular_file).atime, t)
+    assert_equal(File.stat(regular_file).mtime, t)
+    assert_equal(File.lstat(symlinkfile).atime, stat.atime)
+    assert_equal(File.lstat(symlinkfile).mtime, stat.mtime)
+  end
+
+  def test_lutime
+    return unless File.respond_to?(:lutime)
+    return unless symlinkfile
+
+    r = File.stat(regular_file)
+    t = Time.local(2000)
+    File.lutime(t + 1, t + 2, symlinkfile)
+  rescue NotImplementedError => e
+    skip(e.message)
+  else
+    stat = File.stat(regular_file)
+    assert_equal(r.atime, stat.atime)
+    assert_equal(r.mtime, stat.mtime)
+
+    stat = File.lstat(symlinkfile)
+    assert_equal(t + 1, stat.atime)
+    assert_equal(t + 2, stat.mtime)
+  end
+
   def test_hardlink
     return unless hardlinkfile
     assert_equal("file", File.ftype(hardlinkfile))
Index: file.c
===================================================================
--- file.c	(revision 60932)
+++ file.c	(revision 60933)
@@ -2662,6 +2662,7 @@ rb_file_s_lchown(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/file.c#L2662
 struct utime_args {
     const struct timespec* tsp;
     VALUE atime, mtime;
+    int follow; /* Whether to act on symlinks (1) or their referent (0) */
 };
 
 #ifdef UTIME_EINVAL
@@ -2717,11 +2718,27 @@ utime_internal(const char *path, void *a https://github.com/ruby/ruby/blob/trunk/file.c#L2718
 
 #if defined(HAVE_UTIMENSAT)
     static int try_utimensat = 1;
+# ifdef AT_SYMLINK_NOFOLLOW
+    static int try_utimensat_follow = 1;
+# else
+    const int try_utimensat_follow = 0;
+# endif
+    int flags = 0;
+
+    if (v->follow ? try_utimensat_follow : try_utimensat) {
+# ifdef AT_SYMLINK_NOFOLLOW
+	if (v->follow) {
+	    flags = AT_SYMLINK_NOFOLLOW;
+	}
+# endif
 
-    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;
+# ifdef AT_SYMLINK_NOFOLLOW
+		try_utimensat_follow = 0;
+# endif
+		if (!v->follow)
+		    try_utimensat = 0;
                 goto no_utimensat;
             }
             return -1; /* calls utime_failed */
@@ -2738,6 +2755,9 @@ no_utimensat: https://github.com/ruby/ruby/blob/trunk/file.c#L2755
         tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
         tvp = tvbuf;
     }
+#ifdef HAVE_LUTIMES
+    if (v->follow) return lutimes(path, tvp);
+#endif
     return utimes(path, tvp);
 }
 
@@ -2766,17 +2786,8 @@ utime_internal(const char *path, void *a https://github.com/ruby/ruby/blob/trunk/file.c#L2786
 
 #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_i(int argc, VALUE *argv, int follow)
 {
     struct utime_args args;
     struct timespec tss[2], *tsp = NULL;
@@ -2785,6 +2796,8 @@ rb_file_s_utime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/file.c#L2796
     args.atime = *argv++;
     args.mtime = *argv++;
 
+    args.follow = follow;
+
     if (!NIL_P(args.atime) || !NIL_P(args.mtime)) {
 	tsp = tss;
 	tsp[0] = rb_time_timespec(args.atime);
@@ -2798,6 +2811,45 @@ rb_file_s_utime(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/file.c#L2811
     return apply2files(utime_internal, argc, argv, &args);
 }
 
+/*
+ * call-seq:
+ *  File.utime(atime, mtime, file_name,...)   ->  integer
+ *
+ * Sets the access and modification times of each named file to the
+ * first two arguments. If a file is a symlink, this method acts upon
+ * its referent rather than the link itself; for the inverse
+ * behavior see <code>File.lutime</code>. Returns the number of file
+ * names in the argument list.
+ */
+
+static VALUE
+rb_file_s_utime(int argc, VALUE *argv)
+{
+    return utime_internal_i(argc, argv, FALSE);
+}
+
+#if defined(HAVE_UTIMES) && (defined(HAVE_LUTIMES) || (defined(HAVE_UTIMENSAT) && defined(AT_SYMLINK_NOFOLLOW)))
+
+/*
+ * call-seq:
+ *  File.lutime(atime, mtime, file_name,...)   ->  integer
+ *
+ * Sets the access and modification times of each named file to the
+ * first two arguments. If a file is a symlink, this method acts upon
+ * the link itself as opposed to its referent; for the inverse
+ * behavior, see <code>File.utime</code>. Returns the number of file
+ * names in the argument list.
+ */
+
+static VALUE
+rb_file_s_lutime(int argc, VALUE *argv)
+{
+    return utime_internal_i(argc, argv, TRUE);
+}
+#else
+#define rb_file_s_lutime rb_f_notimplement
+#endif
+
 #ifdef RUBY_FUNCTION_NAME_STRING
 # define syserr_fail2(e, s1, s2) syserr_fail2_in(RUBY_FUNCTION_NAME_STRING, e, s1, s2)
 #else
@@ -6259,6 +6311,7 @@ Init_File(void) https://github.com/ruby/ruby/blob/trunk/file.c#L6311
     rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1);
     rb_define_singleton_method(rb_cFile, "lchmod", rb_file_s_lchmod, -1);
     rb_define_singleton_method(rb_cFile, "lchown", rb_file_s_lchown, -1);
+    rb_define_singleton_method(rb_cFile, "lutime", rb_file_s_lutime, -1);
 
     rb_define_singleton_method(rb_cFile, "link", rb_file_s_link, 2);
     rb_define_singleton_method(rb_cFile, "symlink", rb_file_s_symlink, 2);

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]