         o 'length()J', (rs, _this) ->
             fd_obj = _this.get_field rs, 'Ljava/io/RandomAccessFile;fd'
             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
-            gLong.fromNumber (stat_fd fd).size
+            rs.async_op (cb) ->
+              fs.fstat fd, (err, stats) ->
+                cb gLong.fromNumber(stats.size), null
         o 'seek(J)V', (rs, _this, pos) -> _this.$pos = pos.toNumber()
         o 'readBytes([BII)I', (rs, _this, byte_arr, offset, len) ->
             fd_obj = _this.get_field rs, 'Ljava/io/RandomAccessFile;fd'
             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'
-            # if at end of file, return -1.
-            if _this.$pos >= fs.fstatSync(fd).size-1
-              return -1
             buf = new Buffer len
-            bytes_read = fs.readSync(fd, buf, 0, len, _this.$pos)
-            byte_arr.array[offset+i] = buf.readUInt8(i) for i in [0...bytes_read] by 1
-            _this.$pos += bytes_read
-            return if bytes_read == 0 and len isnt 0 then -1 else bytes_read
+            rs.async_op (cb) ->
+              fs.read fd, buf, 0,len, _this.$pos, (err, bytes_read) ->
+                return cb(-1) if err?  # XXX: should check this
+                byte_arr.array[offset+i] = buf.readUInt8(i) for i in [0...bytes_read] by 1
+                _this.$pos += bytes_read
+                cb(if bytes_read == 0 and len isnt 0 then -1 else bytes_read)
         o 'writeBytes([BII)V', (rs, _this, byte_arr, offset, len) ->
             fd_obj = _this.get_field rs, 'Ljava/io/RandomAccessFile;fd'
             fd = fd_obj.get_field rs, 'Ljava/io/FileDescriptor;fd'

              # this is a real file that we've already opened
              pos = _this.$pos
              buf = new Buffer n_bytes
              # if at end of file, return -1.
              filesize = fs.fstatSync(fd).size
              if filesize > 0 and pos >= filesize-1
                return -1
              bytes_read = fs.readSync(fd, buf, 0, n_bytes, pos)
              # not clear why, but sometimes node doesn't move the file pointer,
              # so we do it here ourselves
              _this.$pos += bytes_read
              byte_arr.array[offset+i] = buf.readUInt8(i) for i in [0...bytes_read] by 1
              return if bytes_read == 0 and n_bytes isnt 0 then -1 else bytes_read
            # reading from System.in, do it async
            rs.async_op (cb) ->
              rs.async_input n_bytes, (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
            rs.async_op (cb) ->
              fs.fstat fd, (err, stats) ->
                cb(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
              rs.async_op (cb) ->
                fs.fstat fd, (err, stats) ->
                  buf = new Buffer(stats.size)
                  fs.read fd, buf, 0, 1, _this.$pos, (err, bytes_read) ->
                    _this.$pos++
                    cb(if bytes_read == 0 then -1 else buf.readUInt8(0))
              return
            # reading from System.in, do it async
            rs.async_op (cb) ->
              rs.async_input 1, (byte) ->
