Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ba60fb500eb9
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9f9d1f9a4547
Choose a head ref
  • 2 commits
  • 2 files changed
  • 2 contributors

Commits on Feb 4, 2015

  1. Fix uninitialized usage of File::Stat

    * Fix File::Stat#struct when uninitialized
    * Make other methods fail unless initialized
    lumeet committed Feb 4, 2015
    Copy the full SHA
    f2c7511 View commit details

Commits on Feb 5, 2015

  1. Merge pull request #2560 from lumeet/uninitialized_file_stat

    Fix uninitialized usage of File::Stat
    enebo committed Feb 5, 2015
    Copy the full SHA
    9f9d1f9 View commit details
Showing with 66 additions and 19 deletions.
  1. +66 −18 core/src/main/java/org/jruby/RubyFileStat.java
  2. +0 −1 test/mri/excludes/TestFile.rb
84 changes: 66 additions & 18 deletions core/src/main/java/org/jruby/RubyFileStat.java
Original file line number Diff line number Diff line change
@@ -66,6 +66,10 @@ public class RubyFileStat extends RubyObject {
private FileResource file;
private FileStat stat;

private void checkInitialized() {
if (stat == null) throw getRuntime().newTypeError("uninitialized File::Stat");
}

private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
@@ -148,31 +152,37 @@ public IRubyObject initialize19(IRubyObject fname, Block unusedBlock) {

@JRubyMethod(name = "atime")
public IRubyObject atime() {
checkInitialized();
return getRuntime().newTime(stat.atime() * 1000);
}

@JRubyMethod(name = "blksize")
public RubyFixnum blksize() {
checkInitialized();
return getRuntime().newFixnum(stat.blockSize());
}

@JRubyMethod(name = "blockdev?")
public IRubyObject blockdev_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isBlockDev());
}

@JRubyMethod(name = "blocks")
public IRubyObject blocks() {
checkInitialized();
return getRuntime().newFixnum(stat.blocks());
}

@JRubyMethod(name = "chardev?")
public IRubyObject chardev_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isCharDev());
}

@JRubyMethod(name = "<=>", required = 1)
public IRubyObject cmp(IRubyObject other) {
checkInitialized();
if (!(other instanceof RubyFileStat)) return getRuntime().getNil();

long time1 = stat.mtime();
@@ -189,63 +199,75 @@ public IRubyObject cmp(IRubyObject other) {

@JRubyMethod(name = "ctime")
public IRubyObject ctime() {
checkInitialized();
return getRuntime().newTime(stat.ctime() * 1000);
}

@JRubyMethod(name = "birthtime")
public IRubyObject birthtime() {
checkInitialized();
FileTime btime = RubyFile.getBirthtimeWithNIO(file.absolutePath());
if (btime != null) return getRuntime().newTime(btime.toMillis());
return ctime();
}

@JRubyMethod(name = "dev")
public IRubyObject dev() {
checkInitialized();
return getRuntime().newFixnum(stat.dev());
}

@JRubyMethod(name = "dev_major")
public IRubyObject devMajor() {
checkInitialized();
return getRuntime().newFixnum(stat.major(stat.dev()));
}

@JRubyMethod(name = "dev_minor")
public IRubyObject devMinor() {
checkInitialized();
return getRuntime().newFixnum(stat.minor(stat.dev()));
}

@JRubyMethod(name = "directory?")
public RubyBoolean directory_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isDirectory());
}

@JRubyMethod(name = "executable?")
public IRubyObject executable_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isExecutable());
}

@JRubyMethod(name = "executable_real?")
public IRubyObject executableReal_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isExecutableReal());
}

@JRubyMethod(name = "file?")
public RubyBoolean file_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isFile());
}

@JRubyMethod(name = "ftype")
public RubyString ftype() {
checkInitialized();
return getRuntime().newString(stat.ftype());
}

@JRubyMethod(name = "gid")
public IRubyObject gid() {
checkInitialized();
return getRuntime().newFixnum(stat.gid());
}

@JRubyMethod(name = "grpowned?")
public IRubyObject group_owned_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isGroupOwned());
}

@@ -268,6 +290,7 @@ public IRubyObject initialize_copy(IRubyObject original) {

@JRubyMethod(name = "ino")
public IRubyObject ino() {
checkInitialized();
return getRuntime().newFixnum(stat.ino());
}

@@ -276,41 +299,48 @@ public IRubyObject ino() {
public IRubyObject inspect() {
StringBuilder buf = new StringBuilder("#<");
buf.append(getMetaClass().getRealClass().getName());
buf.append(" ");
// FIXME: Obvious issue that not all platforms can display all attributes. Ugly hacks.
// Using generic posix library makes pushing inspect behavior into specific system impls
// rather painful.
try { buf.append("dev=0x").append(Long.toHexString(stat.dev())); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("ino=").append(stat.ino()); } catch (Exception e) {} finally { buf.append(", "); }
buf.append("mode=0").append(Integer.toOctalString(stat.mode())).append(", ");
try { buf.append("nlink=").append(stat.nlink()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("uid=").append(stat.uid()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("gid=").append(stat.gid()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("rdev=0x").append(Long.toHexString(stat.rdev())); } catch (Exception e) {} finally { buf.append(", "); }
buf.append("size=").append(sizeInternal()).append(", ");
try { buf.append("blksize=").append(stat.blockSize()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("blocks=").append(stat.blocks()); } catch (Exception e) {} finally { buf.append(", "); }

buf.append("atime=").append(atime()).append(", ");
buf.append("mtime=").append(mtime()).append(", ");
buf.append("ctime=").append(ctime());
if (stat == null) {
buf.append(": uninitialized");
} else {
buf.append(" ");
// FIXME: Obvious issue that not all platforms can display all attributes. Ugly hacks.
// Using generic posix library makes pushing inspect behavior into specific system impls
// rather painful.
try { buf.append("dev=0x").append(Long.toHexString(stat.dev())); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("ino=").append(stat.ino()); } catch (Exception e) {} finally { buf.append(", "); }
buf.append("mode=0").append(Integer.toOctalString(stat.mode())).append(", ");
try { buf.append("nlink=").append(stat.nlink()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("uid=").append(stat.uid()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("gid=").append(stat.gid()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("rdev=0x").append(Long.toHexString(stat.rdev())); } catch (Exception e) {} finally { buf.append(", "); }
buf.append("size=").append(sizeInternal()).append(", ");
try { buf.append("blksize=").append(stat.blockSize()); } catch (Exception e) {} finally { buf.append(", "); }
try { buf.append("blocks=").append(stat.blocks()); } catch (Exception e) {} finally { buf.append(", "); }

buf.append("atime=").append(atime()).append(", ");
buf.append("mtime=").append(mtime()).append(", ");
buf.append("ctime=").append(ctime());
}
buf.append(">");

return getRuntime().newString(buf.toString());
}

@JRubyMethod(name = "uid")
public IRubyObject uid() {
checkInitialized();
return getRuntime().newFixnum(stat.uid());
}

@JRubyMethod(name = "mode")
public IRubyObject mode() {
checkInitialized();
return getRuntime().newFixnum(stat.mode());
}

@JRubyMethod(name = "mtime")
public IRubyObject mtime() {
checkInitialized();
return getRuntime().newTime(stat.mtime() * 1000);
}

@@ -328,55 +358,66 @@ public IRubyObject mtimeLessThan(IRubyObject other) {

@JRubyMethod(name = "nlink")
public IRubyObject nlink() {
checkInitialized();
return getRuntime().newFixnum(stat.nlink());
}

@JRubyMethod(name = "owned?")
public IRubyObject owned_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isOwned());
}

@JRubyMethod(name = "pipe?")
public IRubyObject pipe_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isNamedPipe());
}

@JRubyMethod(name = "rdev")
public IRubyObject rdev() {
checkInitialized();
return getRuntime().newFixnum(stat.rdev());
}

@JRubyMethod(name = "rdev_major")
public IRubyObject rdevMajor() {
checkInitialized();
return getRuntime().newFixnum(stat.major(stat.rdev()));
}

@JRubyMethod(name = "rdev_minor")
public IRubyObject rdevMinor() {
checkInitialized();
return getRuntime().newFixnum(stat.minor(stat.rdev()));
}

@JRubyMethod(name = "readable?")
public IRubyObject readable_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isReadable());
}

@JRubyMethod(name = "readable_real?")
public IRubyObject readableReal_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isReadableReal());
}

@JRubyMethod(name = "setgid?")
public IRubyObject setgid_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isSetgid());
}

@JRubyMethod(name = "setuid?")
public IRubyObject setuid_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isSetuid());
}

private long sizeInternal() {
checkInitialized();
// Workaround for JRUBY-4149
if (Platform.IS_WINDOWS && file != null) {
try {
@@ -405,11 +446,13 @@ public IRubyObject size_p() {

@JRubyMethod(name = "socket?")
public IRubyObject socket_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isSocket());
}

@JRubyMethod(name = "sticky?")
public IRubyObject sticky_p() {
checkInitialized();
Ruby runtime = getRuntime();

if (runtime.getPosix().isNative()) {
@@ -421,21 +464,25 @@ public IRubyObject sticky_p() {

@JRubyMethod(name = "symlink?")
public IRubyObject symlink_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isSymlink());
}

@JRubyMethod(name = "writable?")
public IRubyObject writable_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isWritable());
}

@JRubyMethod(name = "writable_real?")
public IRubyObject writableReal_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isWritableReal());
}

@JRubyMethod(name = "zero?")
public IRubyObject zero_p() {
checkInitialized();
return getRuntime().newBoolean(stat.isEmpty());
}

@@ -450,6 +497,7 @@ public IRubyObject worldWritable(ThreadContext context) {
}

private IRubyObject getWorldMode(ThreadContext context, int mode) {
checkInitialized();
if ((stat.mode() & mode) == mode) {
return RubyNumeric.int2fix(context.runtime,
(stat.mode() & (S_IRUGO | S_IWUGO | S_IXUGO) ));
1 change: 0 additions & 1 deletion test/mri/excludes/TestFile.rb
Original file line number Diff line number Diff line change
@@ -10,4 +10,3 @@
exclude :test_s_chown , "needs investigation"
exclude :test_stat , "birthtime does not match MRI behavior (#2152)"
exclude :test_truncate_wbuf, "fails on Linux"
exclude :test_uninitialized , "needs investigation"