8054029: (fc) FileChannel.size() returns 0 for block devices on Linux
authorigerasim
Sat, 13 Sep 2014 20:06:15 +0400
changeset 26618 f30d461d3162
parent 26617 ca6dcc52ff1c
child 26619 28b1c3535fe7
8054029: (fc) FileChannel.size() returns 0 for block devices on Linux Reviewed-by: alanb
jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c
jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java
--- a/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c	Fri Sep 05 19:06:07 2014 -0700
+++ b/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c	Sat Sep 13 20:06:15 2014 +0400
@@ -34,6 +34,10 @@
 #include <fcntl.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#if defined(__linux__)
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#endif
 #include "nio.h"
 #include "nio_util.h"
 
@@ -177,10 +181,21 @@
 JNIEXPORT jlong JNICALL
 Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
 {
+    jint fd = fdval(env, fdo);
     struct stat64 fbuf;
 
-    if (fstat64(fdval(env, fdo), &fbuf) < 0)
+    if (fstat64(fd, &fbuf) < 0)
         return handle(env, -1, "Size failed");
+
+#ifdef BLKGETSIZE64
+    if (S_ISBLK(fbuf.st_mode)) {
+        uint64_t size;
+        if (ioctl(fd, BLKGETSIZE64, &size) < 0)
+            return handle(env, -1, "Size failed");
+        return (jlong)size;
+    }
+#endif
+
     return fbuf.st_size;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/FileChannel/BlockDeviceSize.java	Sat Sep 13 20:06:15 2014 +0400
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8054029
+ * @summary Block devices should not report size=0 on Linux
+ */
+
+import java.io.RandomAccessFile;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.channels.FileChannel;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.NoSuchFileException;
+import static java.nio.file.StandardOpenOption.*;
+
+
+public class BlockDeviceSize {
+    private static final String BLK_FNAME = "/dev/sda1";
+    private static final Path BLK_PATH = Paths.get(BLK_FNAME);
+
+    public static void main(String[] args) throws Throwable {
+        try (FileChannel ch = FileChannel.open(BLK_PATH, READ);
+             RandomAccessFile file = new RandomAccessFile(BLK_FNAME, "r")) {
+
+            long size1 = ch.size();
+            long size2 = file.length();
+            if (size1 != size2) {
+                throw new RuntimeException("size differs when retrieved" +
+                        " in different ways: " + size1 + " != " + size2);
+            }
+            System.out.println("OK");
+
+        } catch (NoSuchFileException nsfe) {
+            System.err.println("File " + BLK_FNAME + " not found." +
+                    " Skipping test");
+        } catch (AccessDeniedException ade) {
+            System.err.println("Access to " + BLK_FNAME + " is denied." +
+                    " Run test as root.");
+        }
+    }
+}