Skip to content

Commit 34fc036

Browse files
committed
[#4710] nanosecond precision in utime using libc futimens
1 parent 8be11ed commit 34fc036

File tree

1 file changed

+34
-41
lines changed

1 file changed

+34
-41
lines changed

core/src/main/java/org/jruby/RubyFile.java

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@
3535
***** END LICENSE BLOCK *****/
3636
package org.jruby;
3737

38+
import jnr.constants.platform.OpenFlags;
39+
import jnr.posix.POSIX;
40+
import jnr.posix.util.Platform;
41+
import org.jcodings.Encoding;
42+
import org.jruby.anno.JRubyClass;
43+
import org.jruby.anno.JRubyMethod;
44+
import org.jruby.runtime.*;
45+
import org.jruby.runtime.JavaSites.FileSites;
46+
import org.jruby.runtime.builtin.IRubyObject;
47+
import org.jruby.runtime.encoding.EncodingCapable;
48+
import org.jruby.runtime.encoding.EncodingService;
49+
import org.jruby.util.*;
50+
import org.jruby.util.io.EncodingUtils;
51+
import org.jruby.util.io.IOEncodable;
52+
import org.jruby.util.io.OpenFile;
53+
import org.jruby.util.io.PosixShim;
54+
3855
import java.io.File;
3956
import java.io.IOException;
4057
import java.io.InputStream;
@@ -58,32 +75,7 @@
5875
import java.util.zip.ZipEntry;
5976
import java.util.zip.ZipFile;
6077

61-
import jnr.constants.platform.OpenFlags;
62-
import jnr.posix.POSIX;
63-
import jnr.posix.util.Platform;
64-
import org.jcodings.Encoding;
65-
import org.jruby.anno.JRubyClass;
66-
import org.jruby.anno.JRubyMethod;
67-
import org.jruby.runtime.Block;
68-
import org.jruby.runtime.ClassIndex;
69-
import org.jruby.runtime.JavaSites.FileSites;
70-
import org.jruby.runtime.ObjectAllocator;
71-
import org.jruby.runtime.ThreadContext;
72-
import static org.jruby.runtime.Visibility.*;
73-
import org.jruby.runtime.builtin.IRubyObject;
74-
import org.jruby.runtime.encoding.EncodingCapable;
75-
import org.jruby.util.ByteList;
76-
import org.jruby.util.FileResource;
77-
import org.jruby.util.JRubyFile;
78-
import org.jruby.util.StringSupport;
79-
import org.jruby.util.TypeConverter;
80-
import org.jruby.util.io.EncodingUtils;
81-
import org.jruby.util.io.IOEncodable;
82-
import org.jruby.util.io.OpenFile;
83-
import org.jruby.runtime.Helpers;
84-
import org.jruby.runtime.encoding.EncodingService;
85-
import org.jruby.util.io.PosixShim;
86-
78+
import static org.jruby.runtime.Visibility.PRIVATE;
8779
import static org.jruby.util.io.EncodingUtils.vmode;
8880
import static org.jruby.util.io.EncodingUtils.vperm;
8981

@@ -1150,12 +1142,12 @@ public static IRubyObject umask(ThreadContext context, IRubyObject recv, IRubyOb
11501142
@JRubyMethod(required = 2, rest = true, meta = true)
11511143
public static IRubyObject utime(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
11521144
Ruby runtime = context.runtime;
1153-
long[] atimeval = null;
1154-
long[] mtimeval = null;
1145+
long[] atimespec = null;
1146+
long[] mtimespec = null;
11551147

11561148
if (args[0] != context.nil || args[1] != context.nil) {
1157-
atimeval = extractTimeval(context, args[0]);
1158-
mtimeval = extractTimeval(context, args[1]);
1149+
atimespec = extractTimespec(context, args[0]);
1150+
mtimespec = extractTimespec(context, args[1]);
11591151
}
11601152

11611153
for (int i = 2, j = args.length; i < j; i++) {
@@ -1167,7 +1159,8 @@ public static IRubyObject utime(ThreadContext context, IRubyObject recv, IRubyOb
11671159
throw runtime.newErrnoENOENTError(filename.toString());
11681160
}
11691161

1170-
int result = runtime.getPosix().utimes(fileToTouch.getAbsolutePath(), atimeval, mtimeval);
1162+
int fd = runtime.getPosix().open(fileToTouch.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0444);
1163+
int result = runtime.getPosix().futimens(fd, atimespec, mtimespec);
11711164
if (result == -1) {
11721165
throw runtime.newErrnoFromInt(runtime.getPosix().errno());
11731166
}
@@ -1552,31 +1545,31 @@ static String adjustRootPathOnWindows(Ruby runtime, String path, String dir) {
15521545
}
15531546

15541547
/**
1555-
* Extract a timeval (an array of 2 longs: seconds and microseconds from epoch) from
1548+
* Extract a timespec (an array of 2 longs: seconds and nanoseconds from epoch) from
15561549
* an IRubyObject.
15571550
*/
1558-
private static long[] extractTimeval(ThreadContext context, IRubyObject value) {
1559-
long[] timeval = new long[2];
1551+
private static long[] extractTimespec(ThreadContext context, IRubyObject value) {
1552+
long[] timespec = new long[2];
15601553

15611554
if (value instanceof RubyFloat) {
1562-
timeval[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
1555+
timespec[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
15631556
double fraction = ((RubyFloat) value).getDoubleValue() % 1.0;
1564-
timeval[1] = (long)(fraction * 1e6 + 0.5);
1557+
timespec[1] = (long)(fraction * 1e9 + 0.5);
15651558
} else if (value instanceof RubyNumeric) {
1566-
timeval[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
1567-
timeval[1] = 0;
1559+
timespec[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
1560+
timespec[1] = 0;
15681561
} else {
15691562
RubyTime time;
15701563
if (value instanceof RubyTime) {
15711564
time = ((RubyTime) value);
15721565
} else {
15731566
time = (RubyTime) TypeConverter.convertToType(context, value, context.runtime.getTime(), sites(context).to_time_checked, true);
15741567
}
1575-
timeval[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.to_i()) : RubyNumeric.num2long(time.to_i());
1576-
timeval[1] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.usec()) : RubyNumeric.num2long(time.usec());
1568+
timespec[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.to_i()) : RubyNumeric.num2long(time.to_i());
1569+
timespec[1] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.nsec()) : RubyNumeric.num2long(time.nsec());
15771570
}
15781571

1579-
return timeval;
1572+
return timespec;
15801573
}
15811574

15821575
private void checkClosed(ThreadContext context) {

0 commit comments

Comments
 (0)