summaryrefslogtreecommitdiff
path: root/file.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-11-19 09:09:38 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-11-19 09:09:38 +0000
commita070c4fbe3cff184d224d1abb8a3101e3c11fc48 (patch)
tree954403e1c09aa8f83d1f153de42e9b7d24f4f289 /file.c
parenta2946d85ec24abd6693a366b78f19cb03acf81b2 (diff)
* configure.in: check struct timespec, clock_gettime, utimensat,
struct stat.st_atim, struct stat.st_atimespec, struct stat.st_atimensec, struct stat.st_mtim, struct stat.st_mtimespec, struct stat.st_mtimensec, struct stat.st_ctim, struct stat.st_ctimespec, struct stat.st_ctimensec. * include/ruby/missing.h: provide struct timespec if not available. * time.c: support nanosecond-resolution using struct timespec. * include/ruby/intern.h: provide rb_time_nano_new. * file.c (utime_internal): use utimensat if available. (rb_file_s_utime): refactored. (rb_f_test): use stat_atime, stat_mtime, stat_ctime. (rb_stat_cmp): check tv_nsec. (stat_atimespec): new function. (stat_atime): ditto. (stat_mtimespec): ditto. (stat_mtime): ditto. (stat_ctimespec): ditto. (stat_ctime): ditto. (rb_stat_atime): use stat_atime. (rb_file_s_atime): ditto. (rb_file_atime): ditto. (rb_stat_mtime): use stat_mtime. (rb_file_s_mtime): ditto. (rb_file_mtime): ditto. (rb_file_ctime): use stat_ctime. (rb_file_s_ctime): ditto. (rb_stat_ctime): ditto. * variable.c (rb_copy_generic_ivar): clear clone's instance variables if obj has no instance variable. * marshal.c (w_object): dump instance variables of generated string for TYPE_USERDEF, even if original object has instance variables. * lib/time.rb (Time#xmlschema): use nsec instead of usec. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13968 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'file.c')
-rw-r--r--file.c193
1 files changed, 134 insertions, 59 deletions
diff --git a/file.c b/file.c
index 3127ecde6b..6f199f6625 100644
--- a/file.c
+++ b/file.c
@@ -43,8 +43,6 @@ int flock(int, int);
#include <time.h>
-VALUE rb_time_new(time_t, time_t);
-
#ifdef HAVE_UTIME_H
#include <utime.h>
#elif defined HAVE_SYS_UTIME_H
@@ -186,6 +184,8 @@ get_stat(VALUE self)
return st;
}
+static struct timespec stat_mtimespec(struct stat *st);
+
/*
* call-seq:
* stat <=> other_stat => -1, 0, 1
@@ -203,14 +203,15 @@ static VALUE
rb_stat_cmp(VALUE self, VALUE other)
{
if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
- time_t t1 = get_stat(self)->st_mtime;
- time_t t2 = get_stat(other)->st_mtime;
- if (t1 == t2)
- return INT2FIX(0);
- else if (t1 < t2)
- return INT2FIX(-1);
- else
- return INT2FIX(1);
+ struct timespec ts1 = stat_mtimespec(get_stat(self));
+ struct timespec ts2 = stat_mtimespec(get_stat(other));
+ if (ts1.tv_sec == ts2.tv_sec) {
+ if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
+ if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
+ return INT2FIX(1);
+ }
+ if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1);
+ return INT2FIX(1);
}
return Qnil;
}
@@ -494,6 +495,77 @@ rb_stat_blocks(VALUE self)
#endif
}
+static struct timespec
+stat_atimespec(struct stat *st)
+{
+ struct timespec ts;
+ ts.tv_sec = st->st_atime;
+#if defined(HAVE_STRUCT_STAT_ST_ATIM)
+ ts.tv_nsec = st->st_atim.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
+ ts.tv_nsec = st->st_atimespec.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
+ ts.tv_nsec = st->st_atimensec;
+#else
+ ts.tv_nsec = 0;
+#endif
+ return ts;
+}
+
+static VALUE
+stat_atime(struct stat *st)
+{
+ struct timespec ts = stat_atimespec(st);
+ return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
+}
+
+static struct timespec
+stat_mtimespec(struct stat *st)
+{
+ struct timespec ts;
+ ts.tv_sec = st->st_mtime;
+#if defined(HAVE_STRUCT_STAT_ST_MTIM)
+ ts.tv_nsec = st->st_mtim.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
+ ts.tv_nsec = st->st_mtimespec.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
+ ts.tv_nsec = st->st_mtimensec;
+#else
+ ts.tv_nsec = 0;
+#endif
+ return ts;
+}
+
+static VALUE
+stat_mtime(struct stat *st)
+{
+ struct timespec ts = stat_mtimespec(st);
+ return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
+}
+
+static struct timespec
+stat_ctimespec(struct stat *st)
+{
+ struct timespec ts;
+ ts.tv_sec = st->st_ctime;
+#if defined(HAVE_STRUCT_STAT_ST_CTIM)
+ ts.tv_nsec = st->st_ctim.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
+ ts.tv_nsec = st->st_ctimespec.tv_nsec;
+#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
+ ts.tv_nsec = st->st_ctimensec;
+#else
+ ts.tv_nsec = 0;
+#endif
+ return ts;
+}
+
+static VALUE
+stat_ctime(struct stat *st)
+{
+ struct timespec ts = stat_ctimespec(st);
+ return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
+}
/*
* call-seq:
@@ -509,7 +581,7 @@ rb_stat_blocks(VALUE self)
static VALUE
rb_stat_atime(VALUE self)
{
- return rb_time_new(get_stat(self)->st_atime, 0);
+ return stat_atime(get_stat(self));
}
/*
@@ -525,7 +597,7 @@ rb_stat_atime(VALUE self)
static VALUE
rb_stat_mtime(VALUE self)
{
- return rb_time_new(get_stat(self)->st_mtime, 0);
+ return stat_mtime(get_stat(self));
}
/*
@@ -543,7 +615,7 @@ rb_stat_mtime(VALUE self)
static VALUE
rb_stat_ctime(VALUE self)
{
- return rb_time_new(get_stat(self)->st_ctime, 0);
+ return stat_ctime(get_stat(self));
}
/*
@@ -1594,7 +1666,7 @@ rb_file_s_atime(VALUE klass, VALUE fname)
if (rb_stat(fname, &st) < 0)
rb_sys_fail(StringValueCStr(fname));
- return rb_time_new(st.st_atime, 0);
+ return stat_atime(&st);
}
/*
@@ -1618,7 +1690,7 @@ rb_file_atime(VALUE obj)
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail(fptr->path);
}
- return rb_time_new(st.st_atime, 0);
+ return stat_atime(&st);
}
/*
@@ -1638,7 +1710,7 @@ rb_file_s_mtime(VALUE klass, VALUE fname)
if (rb_stat(fname, &st) < 0)
rb_sys_fail(RSTRING_PTR(fname));
- return rb_time_new(st.st_mtime, 0);
+ return stat_mtime(&st);
}
/*
@@ -1661,7 +1733,7 @@ rb_file_mtime(VALUE obj)
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail(fptr->path);
}
- return rb_time_new(st.st_mtime, 0);
+ return stat_mtime(&st);
}
/*
@@ -1683,7 +1755,7 @@ rb_file_s_ctime(VALUE klass, VALUE fname)
if (rb_stat(fname, &st) < 0)
rb_sys_fail(RSTRING_PTR(fname));
- return rb_time_new(st.st_ctime, 0);
+ return stat_ctime(&st);
}
/*
@@ -1707,7 +1779,7 @@ rb_file_ctime(VALUE obj)
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail(fptr->path);
}
- return rb_time_new(st.st_ctime, 0);
+ return stat_ctime(&st);
}
static void
@@ -1967,44 +2039,34 @@ rb_file_s_lchown(int argc, VALUE *argv)
}
#endif
-struct timeval rb_time_timeval(VALUE time);
+struct timespec rb_time_timespec(VALUE time);
-#if defined(HAVE_UTIMES) && !defined(__CHECKER__)
+#if defined(HAVE_UTIMENSAT)
static void
utime_internal(const char *path, void *arg)
{
- struct timeval *tvp = arg;
- if (utimes(path, tvp) < 0)
+ struct timespec *tsp = arg;
+ if (utimensat(AT_FDCWD, path, tsp, 0) < 0)
rb_sys_fail(path);
}
-/*
- * 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.
- */
+#elif defined(HAVE_UTIMES)
-static VALUE
-rb_file_s_utime(int argc, VALUE *argv)
+static void
+utime_internal(const char *path, void *arg)
{
- VALUE atime, mtime, rest;
- struct timeval tvs[2], *tvp = NULL;
- long n;
-
- rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
-
- if (!NIL_P(atime) || !NIL_P(mtime)) {
- tvp = tvs;
- tvp[0] = rb_time_timeval(atime);
- tvp[1] = rb_time_timeval(mtime);
+ struct timespec *tsp = arg;
+ struct timeval tvbuf[2], *tvp = arg;
+ if (tsp) {
+ tvbuf[0].tv_sec = tsp[0].tv_sec;
+ tvbuf[0].tv_usec = tsp[0].tv_nsec / 1000;
+ tvbuf[1].tv_sec = tsp[1].tv_sec;
+ tvbuf[1].tv_usec = tsp[1].tv_nsec / 1000;
+ tvp = tvbuf;
}
-
- n = apply2files(utime_internal, rest, tvp);
- return LONG2FIX(n);
+ if (utimes(path, tvp) < 0)
+ rb_sys_fail(path);
}
#else
@@ -2019,34 +2081,47 @@ struct utimbuf {
static void
utime_internal(const char *path, void *arg)
{
- struct utimbuf *utp = arg;
+ struct timespec *tsp = arg;
+ struct utimbuf utbuf, *utp = NULL;
+ if (tsp) {
+ utbuf.actime = tsp[0].tv_sec;
+ utbuf.modtime = tsp[1].tv_sec;
+ utp = &utbuf;
+ }
if (utime(path, utp) < 0)
rb_sys_fail(path);
}
+#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)
{
VALUE atime, mtime, rest;
+ struct timespec tss[2], *tsp = NULL;
long n;
- struct timeval tv;
- struct utimbuf utbuf, *utp = NULL;
rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
if (!NIL_P(atime) || !NIL_P(mtime)) {
- utp = &utbuf;
- tv = rb_time_timeval(atime);
- utp->actime = tv.tv_sec;
- tv = rb_time_timeval(mtime);
- utp->modtime = tv.tv_sec;
+ tsp = tss;
+ tsp[0] = rb_time_timespec(atime);
+ tsp[1] = rb_time_timespec(mtime);
}
- n = apply2files(utime_internal, rest, utp);
+ n = apply2files(utime_internal, rest, tsp);
return LONG2FIX(n);
}
-#endif
NORETURN(static void sys_fail2(VALUE,VALUE));
static void
@@ -3346,11 +3421,11 @@ rb_f_test(int argc, VALUE *argv)
switch (cmd) {
case 'A':
- return rb_time_new(st.st_atime, 0);
+ return stat_atime(&st);
case 'M':
- return rb_time_new(st.st_mtime, 0);
+ return stat_mtime(&st);
case 'C':
- return rb_time_new(st.st_ctime, 0);
+ return stat_ctime(&st);
}
}