Skip to content

Commit

Permalink
[jruby#4710] nanosecond precision in utime using libc futimens
Browse files Browse the repository at this point in the history
  • Loading branch information
alexis779 committed Sep 23, 2017
1 parent 0f9c2a3 commit 850f205
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 43 deletions.
2 changes: 1 addition & 1 deletion core/pom.rb
Expand Up @@ -46,7 +46,7 @@
jar 'com.github.jnr:jnr-enxio:0.16', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-x86asm:1.0.2', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-unixsocket:0.17', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-posix:3.0.41', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-posix:3.0.42', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-constants:0.9.9', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-ffi:2.1.6'
jar 'com.github.jnr:jffi:${jffi.version}'
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Expand Up @@ -135,7 +135,7 @@ DO NOT MODIFIY - GENERATED CODE
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-posix</artifactId>
<version>3.0.41</version>
<version>3.0.42</version>
<exclusions>
<exclusion>
<artifactId>jnr-ffi</artifactId>
Expand Down
75 changes: 34 additions & 41 deletions core/src/main/java/org/jruby/RubyFile.java
Expand Up @@ -35,6 +35,23 @@
***** END LICENSE BLOCK *****/
package org.jruby;

import jnr.constants.platform.OpenFlags;
import jnr.posix.POSIX;
import jnr.posix.util.Platform;
import org.jcodings.Encoding;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.*;
import org.jruby.runtime.JavaSites.FileSites;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.encoding.EncodingCapable;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.util.*;
import org.jruby.util.io.EncodingUtils;
import org.jruby.util.io.IOEncodable;
import org.jruby.util.io.OpenFile;
import org.jruby.util.io.PosixShim;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -58,32 +75,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import jnr.constants.platform.OpenFlags;
import jnr.posix.POSIX;
import jnr.posix.util.Platform;
import org.jcodings.Encoding;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.Block;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.JavaSites.FileSites;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import static org.jruby.runtime.Visibility.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.encoding.EncodingCapable;
import org.jruby.util.ByteList;
import org.jruby.util.FileResource;
import org.jruby.util.JRubyFile;
import org.jruby.util.StringSupport;
import org.jruby.util.TypeConverter;
import org.jruby.util.io.EncodingUtils;
import org.jruby.util.io.IOEncodable;
import org.jruby.util.io.OpenFile;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.util.io.PosixShim;

import static org.jruby.runtime.Visibility.PRIVATE;
import static org.jruby.util.io.EncodingUtils.vmode;
import static org.jruby.util.io.EncodingUtils.vperm;

Expand Down Expand Up @@ -1150,12 +1142,12 @@ public static IRubyObject umask(ThreadContext context, IRubyObject recv, IRubyOb
@JRubyMethod(required = 2, rest = true, meta = true)
public static IRubyObject utime(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
long[] atimeval = null;
long[] mtimeval = null;
long[] atimespec = null;
long[] mtimespec = null;

if (args[0] != context.nil || args[1] != context.nil) {
atimeval = extractTimeval(context, args[0]);
mtimeval = extractTimeval(context, args[1]);
atimespec = extractTimespec(context, args[0]);
mtimespec = extractTimespec(context, args[1]);
}

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

int result = runtime.getPosix().utimes(fileToTouch.getAbsolutePath(), atimeval, mtimeval);
int fd = runtime.getPosix().open(fileToTouch.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0444);
int result = runtime.getPosix().futimens(fd, atimespec, mtimespec);
if (result == -1) {
throw runtime.newErrnoFromInt(runtime.getPosix().errno());
}
Expand Down Expand Up @@ -1552,31 +1545,31 @@ static String adjustRootPathOnWindows(Ruby runtime, String path, String dir) {
}

/**
* Extract a timeval (an array of 2 longs: seconds and microseconds from epoch) from
* Extract a timespec (an array of 2 longs: seconds and nanoseconds from epoch) from
* an IRubyObject.
*/
private static long[] extractTimeval(ThreadContext context, IRubyObject value) {
long[] timeval = new long[2];
private static long[] extractTimespec(ThreadContext context, IRubyObject value) {
long[] timespec = new long[2];

if (value instanceof RubyFloat) {
timeval[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
timespec[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
double fraction = ((RubyFloat) value).getDoubleValue() % 1.0;
timeval[1] = (long)(fraction * 1e6 + 0.5);
timespec[1] = (long)(fraction * 1e9 + 0.5);
} else if (value instanceof RubyNumeric) {
timeval[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
timeval[1] = 0;
timespec[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(value) : RubyNumeric.num2long(value);
timespec[1] = 0;
} else {
RubyTime time;
if (value instanceof RubyTime) {
time = ((RubyTime) value);
} else {
time = (RubyTime) TypeConverter.convertToType(context, value, context.runtime.getTime(), sites(context).to_time_checked, true);
}
timeval[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.to_i()) : RubyNumeric.num2long(time.to_i());
timeval[1] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.usec()) : RubyNumeric.num2long(time.usec());
timespec[0] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.to_i()) : RubyNumeric.num2long(time.to_i());
timespec[1] = Platform.IS_32_BIT ? RubyNumeric.num2int(time.nsec()) : RubyNumeric.num2long(time.nsec());
}

return timeval;
return timespec;
}

private void checkClosed(ThreadContext context) {
Expand Down

0 comments on commit 850f205

Please sign in to comment.