JDK-8054029 : (fc) FileChannel.size() returns 0 for block devices on Linux
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2012-08-24
  • Updated: 2015-06-04
  • Resolved: 2014-09-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u40Fixed 9 b32Fixed
Description
FULL PRODUCT VERSION :
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) 64-Bit Server VM (build 22.1-b02, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Linux XXX 3.0.0-21-generic #35-Ubuntu SMP Fri May 25 17:57:41 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
FileChannel.size() returns 0 for block devices on Linux. As a consequence, it is impossible to memory map a block device, because FileChannel.map() uses size() to determine whether the file is big enough, and in the case of a block device, since size() always returns 0, it always concludes that it isn't big enough, tries to enlarge it, and fails.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
On Linux, compile the sample code and execute it using a command similar to this:

sudo java -cp . BlockDeviceBug /dev/sda

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
It should show something like this:

File: /dev/sda
Size: 500107862016
Actual size: 500107862016
ACTUAL -
It actually says:

File: /dev/sda
Size: 0
Actual size: 500107862016

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class BlockDeviceBug {
    public static void main(String[] args) throws IOException {
        try (RandomAccessFile file = new RandomAccessFile(args[0], "r")) {
            FileChannel channel = file.getChannel();
            System.out.println("File: " + args[0]);
            System.out.println("Size according to FileChannel: " + channel.size());
            System.out.println("Actual size: " + file.length());
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround found.

Comments
This is not an issue on Solaris: stat /devices/pci@1c,600000/scsi@2/sd@0,0:a File: `/devices/pci@1c,600000/scsi@2/sd@0,0:a' Size: 10738040832 Blocks: 0 IO Block: 8192 block special file Files.size(new File("/devices/pci@1c,600000/scsi@2/sd@0,0:a").toPath()) returns the same number of bytes.
12-09-2014

FileChannel.size() result is in line with what java.nio.file.Files.size() and java.nio.file.Files.readAttributes() return. They all report zero size for the block devices because that's what stat()/fstat() calls do. RandomAccessFile uses lseek to determine the furthest position in the file, so it can figure out the file's size. However, using lseek is, first, racy and, second, couldn't be used by java.nio.file.Files.readAttributes() anyway (it would require an additional access permission to open the file).
13-08-2014