             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
             rs.java_throw rs.get_bs_class('Ljava/io/IOException;'), "Bad file descriptor" if fd is -1
             unless fd is 0
-              bytes_left = fs.fstatSync(fd).size - _this.$pos
-              to_skip = Math.min(n_bytes.toNumber(), bytes_left)
-              _this.$pos += to_skip
-              return gLong.fromNumber(to_skip)
+              rs.async_op (cb) ->
+                fs.fstat fd, (err, stats) ->
+                  bytes_left = stats.size - _this.$pos
+                  to_skip = Math.min(n_bytes.toNumber(), bytes_left)
+                  _this.$pos += to_skip
+                  cb gLong.fromNumber(to_skip), null
+              return
             # reading from System.in, do it async
             rs.async_op (cb) ->
               rs.async_input n_bytes.toNumber(), (bytes) ->

            fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
            rs.java_throw rs.get_bs_class('Ljava/io/IOException;'), "Bad file descriptor" if fd is -1
            return 0 if fd is 0 # no buffering for stdin
            stats = fs.fstatSync fd
            stats.size - _this.$pos
        o 'read()I', (rs, _this) ->
            fd_obj = _this.get_field rs, 'Ljava/io/FileInputStream;fd'
            fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
            rs.java_throw rs.get_bs_class('Ljava/io/IOException;'), "Bad file descriptor" if fd is -1
            unless fd is 0
              # this is a real file that we've already opened
              buf = new Buffer((fs.fstatSync fd).size)
              bytes_read = fs.readSync(fd, buf, 0, 1, _this.$pos)
              _this.$pos++
              return if bytes_read == 0 then -1 else buf.readUInt8(0)
            # reading from System.in, do it async
            rs.async_op (cb) ->
              rs.async_input 1, (byte) ->

          rs.meta_stack().push {}  # dummy
          resume_cb()),
        except_cb

stat_file = (fname, cb) ->
  fs.stat fname, (err, stat) ->
