diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | configure.in | 1 | ||||
-rw-r--r-- | file.c | 112 | ||||
-rw-r--r-- | test/ruby/test_file.rb | 25 |
5 files changed, 158 insertions, 1 deletions
@@ -1,3 +1,15 @@ +Thu May 22 20:38:10 2014 NARUSE, Yui <[email protected]> + + * 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 <[email protected]> * file.c: remove IO::Statfs because of reject. [Feature #9772] @@ -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> @@ -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| |