JDK-6253145 : (fc) FileChannel.transferTo on Linux fails when going beyond 2GB boundary
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.2,5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,solaris_7,solaris_9
  • CPU: x86,sparc
  • Submitted: 2005-04-11
  • Updated: 2011-05-17
  • Resolved: 2011-05-17
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 6 JDK 7
6u18Fixed 7 b07Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_01-b08)
Java HotSpot(TM) Client VM (build 1.5.0_01-b08, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Linux SageTVMediaCenter 2.6.11 #4 Thu Mar 17 00:22:15 GMT 2005 i686 VIA Nehemiah CentaurHauls GNU/Linux

A DESCRIPTION OF THE PROBLEM :
When using java.nio.channels.FileChannel.transferTo(long offset, long length, WritableByteChannel ch) with an offset greater than 2^32 the data that's actually transferred is not the correct data.  It ends up doing a modulus with 2^32 and only transferring data from within the first 2GB of the file.

This happens because in the JNI code for this on Linux it's using the sendfile() Linux API call. This call is not compliant with 64-bit offsets.

  From FileChannelImpl.c:

JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,
					    jint srcFD,
					    jlong position, jlong count,
					    jint dstFD)
{
#ifdef __linux__
    off_t offset = (off_t)position;
    jlong n = sendfile(dstFD, srcFD, &offset, (size_t)count);
    if (n < 0) {
        jlong max = (jlong)java_lang_Integer_MAX_VALUE;
        if (count > max) {
            n = sendfile(dstFD, srcFD, &offset, (size_t)max);
            if (n >= 0) {
                return n;
            }
        }
        if ((errno == EINVAL) && ((ssize_t)count >= 0))
            return IOS_UNSUPPORTED_CASE;
	JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
    }
    return n;
#endif

...


REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
Don't use transferTo when transferring data that lies beyond the 2GB boundary.
###@###.### 2005-04-11 10:25:03 GMT

Comments
EVALUATION The 2.6 kernel has a sendfile64 so we should use that where available. Where not available we need to handle the offset > 2GB case. This is something for early in jdk7 so that it gets well tested.
02-12-2006