summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--NEWS9
-rw-r--r--configure.in1
-rw-r--r--file.c112
-rw-r--r--test/ruby/test_file.rb25
5 files changed, 158 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index fbd4a0db13..2ff26bd37f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Thu May 22 20:38:10 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (stat_birthtime): add birthtime support [Feature #9647]
+
+ * file.c (rb_stat_birthtime): add File::Stat.birthtime
+
+ * file.c (rb_file_s_birthtime): add File.birthtime
+
+ * file.c (rb_file_birthtime): add File#birthtime
+
+ * configure.in: check struct stat.st_birthtimespec.
+
Thu May 22 19:38:14 2014 NARUSE, Yui <naruse@ruby-lang.org>
* file.c: remove IO::Statfs because of reject. [Feature #9772]
diff --git a/NEWS b/NEWS
index 0fd7b01c5c..8bc0625f8a 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,15 @@ with all sufficient information, see the ChangeLog file.
* Float#next_float
* Float#prev_float
+* File
+ * New methods:
+ * File.birthtime
+ * File#birthtime
+
+* File::Stat
+ * New methods:
+ * File::Stat#birthtime
+
* Process
* Extended method:
* Process execution methods such as Process.spawn opens the file in write
diff --git a/configure.in b/configure.in
index 91b6cf0286..9a4c963f77 100644
--- a/configure.in
+++ b/configure.in
@@ -1696,6 +1696,7 @@ AC_CHECK_MEMBERS([struct stat.st_mtimensec])
AC_CHECK_MEMBERS([struct stat.st_ctim])
AC_CHECK_MEMBERS([struct stat.st_ctimespec])
AC_CHECK_MEMBERS([struct stat.st_ctimensec])
+AC_CHECK_MEMBERS([struct stat.st_birthtimespec])
AC_CHECK_TYPES([struct timeval], [], [], [@%:@ifdef HAVE_TIME_H
@%:@include <time.h>
diff --git a/file.c b/file.c
index af42d98dfb..2305066970 100644
--- a/file.c
+++ b/file.c
@@ -782,6 +782,19 @@ stat_ctime(struct stat *st)
return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
}
+#define HAVE_STAT_BIRTHTIME
+#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
+static VALUE
+stat_birthtime(struct stat *st)
+{
+ struct timespec *ts = &st->st_birthtimespec;
+ return rb_time_nano_new(ts->tv_sec, ts->tv_nsec);
+}
+#elif defined(_WIN32)
+#else
+# undef HAVE_STAT_BIRTHTIME
+#endif
+
/*
* call-seq:
* stat.atime -> time
@@ -836,6 +849,37 @@ rb_stat_ctime(VALUE self)
}
/*
+ * call-seq:
+ * stat.birthtime -> aTime
+ *
+ * Returns the birth time for <i>stat</i>.
+ * If the platform doesn't have birthtime, returns <i>ctime</i>.
+ *
+ * File.write("testfile", "foo")
+ * sleep 10
+ * File.write("testfile", "bar")
+ * sleep 10
+ * File.chmod(0644, "testfile")
+ * sleep 10
+ * File.read("testfile")
+ * File.stat("testfile").birthtime #=> 2014-02-24 11:19:17 +0900
+ * File.stat("testfile").mtime #=> 2014-02-24 11:19:27 +0900
+ * File.stat("testfile").ctime #=> 2014-02-24 11:19:37 +0900
+ * File.stat("testfile").atime #=> 2014-02-24 11:19:47 +0900
+ *
+ */
+
+#if defined(HAVE_STAT_BIRTHTIME)
+static VALUE
+rb_stat_birthtime(VALUE self)
+{
+ return stat_birthtime(get_stat(self));
+}
+#else
+# define rb_stat_birthtime rb_f_notimplement
+#endif
+
+/*
* call-seq:
* stat.inspect -> string
*
@@ -846,7 +890,8 @@ rb_stat_ctime(VALUE self)
* # nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096,
* # blocks=8, atime=Wed Dec 10 10:16:12 CST 2003,
* # mtime=Fri Sep 12 15:41:41 CDT 2003,
- * # ctime=Mon Oct 27 11:20:27 CST 2003>"
+ * # ctime=Mon Oct 27 11:20:27 CST 2003,
+ * # birthtime=Mon Aug 04 08:13:49 CDT 2003>"
*/
static VALUE
@@ -871,6 +916,9 @@ rb_stat_inspect(VALUE self)
{"atime", rb_stat_atime},
{"mtime", rb_stat_mtime},
{"ctime", rb_stat_ctime},
+#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
+ {"birthtime", rb_stat_birthtime},
+#endif
};
struct stat* st;
@@ -2084,6 +2132,65 @@ rb_file_ctime(VALUE obj)
/*
* call-seq:
+ * File.birthtime(file_name) -> time
+ *
+ * Returns the birth time for the named file.
+ *
+ * _file_name_ can be an IO object.
+ *
+ * Note that on Windows (NTFS), returns creation time (birth time).
+ *
+ * File.birthtime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
+ *
+ */
+
+#if defined(HAVE_STAT_BIRTHTIME)
+static VALUE
+rb_file_s_birthtime(VALUE klass, VALUE fname)
+{
+ struct stat st;
+
+ if (rb_stat(fname, &st) < 0) {
+ FilePathValue(fname);
+ rb_sys_fail_path(fname);
+ }
+ return stat_birthtime(&st);
+}
+#else
+# define rb_file_s_birthtime rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
+ * file.birthtime -> time
+ *
+ * Returns the birth time for <i>file</i>.
+ *
+ * Note that on Windows (NTFS), returns creation time (birth time).
+ *
+ * File.new("testfile").birthtime #=> Wed Apr 09 08:53:14 CDT 2003
+ *
+ */
+
+#if defined(HAVE_STAT_BIRTHTIME)
+static VALUE
+rb_file_birthtime(VALUE obj)
+{
+ rb_io_t *fptr;
+ struct stat st;
+
+ GetOpenFile(obj, fptr);
+ if (fstat(fptr->fd, &st) == -1) {
+ rb_sys_fail_path(fptr->pathv);
+ }
+ return stat_birthtime(&st);
+}
+#else
+# define rb_file_birthtime rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
* file.size -> integer
*
* Returns the size of <i>file</i> in bytes.
@@ -5646,6 +5753,7 @@ Init_File(void)
rb_define_singleton_method(rb_cFile, "atime", rb_file_s_atime, 1);
rb_define_singleton_method(rb_cFile, "mtime", rb_file_s_mtime, 1);
rb_define_singleton_method(rb_cFile, "ctime", rb_file_s_ctime, 1);
+ rb_define_singleton_method(rb_cFile, "birthtime", rb_file_s_birthtime, 1);
rb_define_singleton_method(rb_cFile, "utime", rb_file_s_utime, -1);
rb_define_singleton_method(rb_cFile, "chmod", rb_file_s_chmod, -1);
@@ -5693,6 +5801,7 @@ Init_File(void)
rb_define_method(rb_cFile, "atime", rb_file_atime, 0);
rb_define_method(rb_cFile, "mtime", rb_file_mtime, 0);
rb_define_method(rb_cFile, "ctime", rb_file_ctime, 0);
+ rb_define_method(rb_cFile, "birthtime", rb_file_birthtime, 0);
rb_define_method(rb_cFile, "size", rb_file_size, 0);
rb_define_method(rb_cFile, "chmod", rb_file_chmod, 1);
@@ -5814,6 +5923,7 @@ Init_File(void)
rb_define_method(rb_cStat, "atime", rb_stat_atime, 0);
rb_define_method(rb_cStat, "mtime", rb_stat_mtime, 0);
rb_define_method(rb_cStat, "ctime", rb_stat_ctime, 0);
+ rb_define_method(rb_cStat, "birthtime", rb_stat_birthtime, 0);
rb_define_method(rb_cStat, "inspect", rb_stat_inspect, 0);
diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb
index 01992a83d4..6e0930f955 100644
--- a/test/ruby/test_file.rb
+++ b/test/ruby/test_file.rb
@@ -311,6 +311,31 @@ class TestFile < Test::Unit::TestCase
assert_equal(mod_time_contents, stats.mtime, bug6385)
end
+ def test_stat
+ file = Tempfile.new("stat")
+ file.close
+ path = file.path
+
+ t0 = Process.clock_gettime(Process::CLOCK_REALTIME)
+ File.write(path, "foo")
+ sleep 2
+ File.write(path, "bar")
+ sleep 2
+ File.chmod(0644, path)
+ sleep 2
+ File.read(path)
+
+ delta = 1
+ stat = File.stat(path)
+ if stat.birthtime != stat.ctime
+ assert_in_delta t0, stat.birthtime.to_f, delta
+ end
+ assert_in_delta t0+2, stat.mtime.to_f, delta
+ assert_in_delta t0+4, stat.ctime.to_f, delta
+ assert_in_delta t0+6, stat.atime.to_f, delta
+ rescue NotImplementedError
+ end
+
def test_chmod_m17n
bug5671 = '[ruby-dev:44898]'
Dir.mktmpdir('test-file-chmod-m17n-') do |tmpdir|