1 /*
   2  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4475533 4698138 4638365 4796221
  27  * @summary Test FileChannel write
  28  * @run main/othervm Write
  29  */
  30 
  31 import java.nio.channels.*;
  32 import java.nio.*;
  33 import java.io.*;
  34 
  35 public class Write {
  36 
  37    public static void main(String[] args) throws Exception {
  38        test1(); // for bug 4475533
  39        test2();
  40        test3(); // for bug 4698138
  41 
  42        // This test is not suitable for automated testing at this time.
  43        // I am commenting it out but it will be easy to manually
  44        // test for a regression in this area. See also 4796221.
  45        //test4(); // for bug 4638365
  46    }
  47 
  48     // Test to see that offset > length does not throw exception
  49     static void test1() throws Exception {
  50         ByteBuffer[] dsts = new ByteBuffer[4];
  51         for (int i=0; i<4; i++)
  52             dsts[i] = ByteBuffer.allocateDirect(10);
  53 
  54         File testFile = File.createTempFile("test1", null);
  55         try {
  56             FileOutputStream fos = new FileOutputStream(testFile);
  57             FileChannel fc = fos.getChannel();
  58             fc.write(dsts, 2, 1);
  59             fos.close();
  60         } finally {
  61             testFile.delete();
  62         }
  63     }
  64 
  65     // Test to see that the appropriate buffers are updated
  66     static void test2() throws Exception {
  67         File testFile = File.createTempFile("test2", null);
  68         testFile.delete();
  69         ByteBuffer[] srcs = new ByteBuffer[4];
  70         for (int i=0; i<4; i++)
  71             srcs[i] = ByteBuffer.allocateDirect(10);
  72 
  73         srcs[0].put((byte)1); srcs[0].flip();
  74         srcs[1].put((byte)2); srcs[1].flip();
  75         srcs[2].put((byte)3); srcs[2].flip();
  76         srcs[3].put((byte)4); srcs[3].flip();
  77 
  78         FileOutputStream fos = new FileOutputStream(testFile);
  79         FileChannel fc = fos.getChannel();
  80         try {
  81             fc.write(srcs, 1, 2);
  82         } finally {
  83             fc.close();
  84         }
  85 
  86         FileInputStream fis = new FileInputStream(testFile);
  87         fc = fis.getChannel();
  88         try {
  89             ByteBuffer bb = ByteBuffer.allocateDirect(10);
  90             fc.read(bb);
  91             bb.flip();
  92             if (bb.get() != 2)
  93                 throw new RuntimeException("Write failure");
  94             if (bb.get() != 3)
  95                 throw new RuntimeException("Write failure");
  96             try {
  97                 bb.get();
  98                 throw new RuntimeException("Write failure");
  99             } catch (BufferUnderflowException bufe) {
 100                 // correct result
 101             }
 102         } finally {
 103             fc.close();
 104         }
 105 
 106         // eagerly clean-up
 107         testFile.delete();
 108     }
 109 
 110     // Test write to a negative position (bug 4698138).
 111     static void test3() throws Exception {
 112         File testFile = File.createTempFile("test1", null);
 113         testFile.deleteOnExit();
 114         ByteBuffer dst = ByteBuffer.allocate(10);
 115         FileOutputStream fos = new FileOutputStream(testFile);
 116         FileChannel fc = fos.getChannel();
 117         try {
 118             fc.write(dst, -1);
 119             throw new RuntimeException("Expected IAE not thrown");
 120         } catch (IllegalArgumentException iae) {
 121             // Correct result
 122         } finally {
 123             fos.close();
 124         }
 125     }
 126 
 127     private static final int TEST4_NUM_BUFFERS = 3;
 128 
 129     private static final int TEST4_BUF_CAP = Integer.MAX_VALUE / 2;
 130 
 131     /**
 132      * Test to see that vector write can return > Integer.MAX_VALUE
 133      *
 134      * Note that under certain circumstances disk space problems occur
 135      * with this test. It typically relies upon adequate disk space and/or
 136      * a Solaris disk space optimization where empty files take up less
 137      * space than their logical size.
 138      *
 139      * Note that if this test fails it is not necessarily a violation of
 140      * spec: the value returned by fc.write can be smaller than the number
 141      * of bytes requested to write. It is testing an optimization that allows
 142      * for larger return values.
 143      */
 144     static void test4() throws Exception {
 145         // Only works on 64 bit Solaris
 146         String osName = System.getProperty("os.name");
 147         if (!osName.startsWith("SunOS"))
 148             return;
 149         String dataModel = System.getProperty("sun.arch.data.model");
 150         if (!dataModel.startsWith("64"))
 151             return;
 152 
 153         File testFile = File.createTempFile("test4", null);
 154         testFile.deleteOnExit();
 155 
 156         FileChannel[] fcs = new FileChannel[TEST4_NUM_BUFFERS];
 157 
 158         ByteBuffer[] dsts = new ByteBuffer[TEST4_NUM_BUFFERS];
 159         // Map these buffers from a file so we don't run out of memory
 160         for (int i=0; i<TEST4_NUM_BUFFERS; i++) {
 161             File f = File.createTempFile("test4." + i, null);
 162             f.deleteOnExit();
 163             prepTest4File(f);
 164             FileInputStream fis = new FileInputStream(f);
 165             FileChannel fc = fis.getChannel();
 166             MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0,
 167                                           TEST4_BUF_CAP);
 168             dsts[i] = mbb;
 169         }
 170 
 171         FileOutputStream fos = new FileOutputStream(testFile);
 172         FileChannel fc = fos.getChannel();
 173         try {
 174             long bytesWritten = fc.write(dsts);
 175             if (bytesWritten < Integer.MAX_VALUE) {
 176                 // Note: this is not a violation of the spec
 177                 throw new RuntimeException("Test 4 failed but wrote " +
 178                                            bytesWritten);
 179             }
 180         } finally {
 181             fc.close();
 182             fos.close();
 183         }
 184     }
 185 
 186     static void prepTest4File(File blah) throws Exception {
 187         RandomAccessFile raf = new RandomAccessFile(blah, "rw");
 188         FileChannel fc = raf.getChannel();
 189         fc.write(ByteBuffer.wrap("Use the source!".getBytes()),
 190                  TEST4_BUF_CAP);
 191         fc.close();
 192         raf.close();
 193     }
 194 
 195 }