This must have been on somebody's plate for a long time.

Attached please find a patch to correct an apparently unreported bug. At least, I couldn't find one. The problem is that if a FileChannel is truncated and its position was previously set beyond the new length of the file, the position should be but isn't set to the new length of the file.

Heads up. I have kinda sorta tested this patch. I run a Mac OS X Leopard system. I have tested this patch on that system, as applied to the soylatte source code repository. More info on soylatte here: http://landonf.bikemonkey.org/static/soylatte/. The gist of it is that soylatte is a port of Sun's JDK 6 to Mac OS X. My test procedure was as follows:

1. Get jdk7/jdk/test/java/nio/channels/FileChannel/Truncate.java from the OpenJDK repository.

2. Compile and run Truncate on soylatte 1.0.1 (which is based on Sun's JDK 6 something). Test reports failure as such:

Exception in thread "main" java.lang.RuntimeException: Position greater than size
        at Truncate.main(Truncate.java:68)

3. Run Truncate on a patched version of soylatte (patch essentially identical to attached file). Test completes normally without output. I guess this means it passed.

I'm sending this in as a patch to OpenJDK and not soylatte because I know this is a problem on Solaris, too. That is, I ran Truncate on jdk6u4 on solaris 11 and it failed.

Obviously, this is not the only way to fix this problem. We could also do this with a patch to FileChannelImpl.java. I'll let whoever's in charge here make that call.

So, I hope this is helpful. I am ready and willing to respond to feedback. I have tried to follow the guidelines in http://openjdk.java.net/contribute/.

Cheers,

Michael

(CCing Landon Fuller because he runs the Soylatte project.)
diff --git a/src/solaris/native/sun/nio/ch/FileChannelImpl.c b/src/solaris/native/sun/nio/ch/FileChannelImpl.c
--- a/src/solaris/native/sun/nio/ch/FileChannelImpl.c
+++ b/src/solaris/native/sun/nio/ch/FileChannelImpl.c
@@ -148,9 +148,32 @@ Java_sun_nio_ch_FileChannelImpl_truncate
 Java_sun_nio_ch_FileChannelImpl_truncate0(JNIEnv *env, jobject this,
                                           jobject fdo, jlong size)
 {
-    return handle(env,
-                  ftruncate64(fdval(env, fdo), size),
-                  "Truncation failed");
+    jlong result;
+
+    jint fd = fdval(env, fdo);
+    jlong ftruncateResult = ftruncate64(fd, size);
+
+    if (ftruncateResult < 0) {
+        result = handle(env, ftruncateResult, "Truncation failed");
+    } else {
+        jlong position = lseek64(fd, 0, SEEK_CUR);
+
+        if (position < 0) {
+            result = handle(env, position, "Truncation succeeded, but repositioning failed");
+        } else if (position > size) {
+            jlong newPosition = lseek64(fd, size, SEEK_SET);
+
+            if (newPosition < 0) {
+                result = handle(env, newPosition, "Truncation succeeded, but repositioning failed");
+            } else {
+                result = ftruncateResult;
+            }
+        } else {
+            result = ftruncateResult;
+        }
+    }
+
+    return result;
 }
 
 

Reply via email to