1 /*
   2  * Copyright (c) 2008, 2011, 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 /* @test
  25  * @bug 4313887
  26  * @summary Unit test for java.nio.file.Files.newByteChannel
  27  * @library ..
  28  */
  29 
  30 import java.nio.ByteBuffer;
  31 import java.nio.file.*;
  32 import static java.nio.file.StandardOpenOption.*;
  33 import static com.sun.nio.file.ExtendedOpenOption.*;
  34 import java.nio.file.attribute.FileAttribute;
  35 import java.nio.channels.*;
  36 import java.io.IOException;
  37 import java.util.*;
  38 
  39 public class SBC {
  40 
  41     static boolean supportsLinks;
  42 
  43     public static void main(String[] args) throws Exception {
  44         Path dir = TestUtil.createTemporaryDirectory();
  45         try {
  46             supportsLinks = TestUtil.supportsLinks(dir);
  47 
  48             // open options
  49             createTests(dir);
  50             appendTests(dir);
  51             truncateExistingTests(dir);
  52             noFollowLinksTests(dir);
  53 
  54             // SeekableByteChannel methods
  55             sizeTruncatePositionTests(dir);
  56 
  57             // platform specific
  58             if (System.getProperty("os.name").startsWith("Windows"))
  59                 dosSharingOptionTests(dir);
  60 
  61             // misc. tests
  62             badCombinations(dir);
  63             unsupportedOptions(dir);
  64             nullTests(dir);
  65 
  66         } finally {
  67             TestUtil.removeAll(dir);
  68         }
  69     }
  70 
  71     // test CREATE and CREATE_NEW options
  72     static void createTests(Path dir) throws Exception {
  73         Path file = dir.resolve("foo");
  74 
  75         // CREATE
  76         try {
  77             // create file (no existing file)
  78             Files.newByteChannel(file, CREATE, WRITE).close();
  79             if (Files.notExists(file))
  80                 throw new RuntimeException("File not created");
  81 
  82             // create file (existing file)
  83             Files.newByteChannel(file, CREATE, WRITE).close();
  84 
  85             // create file where existing file is a sym link
  86             if (supportsLinks) {
  87                 Path link = Files.createSymbolicLink(dir.resolve("link"), file);
  88                 try {
  89                     // file already exists
  90                     Files.newByteChannel(link, CREATE, WRITE).close();
  91 
  92                     // file does not exist
  93                     Files.delete(file);
  94                     Files.newByteChannel(link, CREATE, WRITE).close();
  95                     if (Files.notExists(file))
  96                         throw new RuntimeException("File not created");
  97 
  98                 } finally {
  99                     TestUtil.deleteUnchecked(link);
 100                 }
 101             }
 102 
 103         } finally {
 104             TestUtil.deleteUnchecked(file);
 105         }
 106 
 107         // CREATE_NEW
 108         try {
 109             // create file
 110             Files.newByteChannel(file, CREATE_NEW, WRITE).close();
 111             if (Files.notExists(file))
 112                 throw new RuntimeException("File not created");
 113 
 114             // create should fail
 115             try {
 116                 SeekableByteChannel sbc =
 117                     Files.newByteChannel(file, CREATE_NEW, WRITE);
 118                 sbc.close();
 119                 throw new RuntimeException("FileAlreadyExistsException not thrown");
 120             } catch (FileAlreadyExistsException x) { }
 121 
 122             // create should fail
 123             if (supportsLinks) {
 124                 Path link = dir.resolve("link");
 125                 Path target = dir.resolve("thisDoesNotExist");
 126                 Files.createSymbolicLink(link, target);
 127                 try {
 128 
 129                     try {
 130                         SeekableByteChannel sbc =
 131                             Files.newByteChannel(file, CREATE_NEW, WRITE);
 132                         sbc.close();
 133                         throw new RuntimeException("FileAlreadyExistsException not thrown");
 134                     } catch (FileAlreadyExistsException x) { }
 135 
 136                 } finally {
 137                     TestUtil.deleteUnchecked(link);
 138                 }
 139             }
 140 
 141 
 142         } finally {
 143             TestUtil.deleteUnchecked(file);
 144         }
 145 
 146         // CREATE_NEW + SPARSE
 147         try {
 148             try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, WRITE, SPARSE)) {
 149                 final long hole = 2L * 1024L * 1024L * 1024L;
 150                 sbc.position(hole);
 151                 write(sbc, "hello");
 152                 long size = sbc.size();
 153                 if (size != (hole + 5))
 154                     throw new RuntimeException("Unexpected size");
 155             }
 156         } finally {
 157             TestUtil.deleteUnchecked(file);
 158         }
 159     }
 160 
 161     // test APPEND option
 162     static void appendTests(Path dir) throws Exception {
 163         Path file = dir.resolve("foo");
 164         try {
 165             // "hello there" should be written to file
 166             try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, WRITE, APPEND)) {
 167                 write(sbc, "hello ");
 168                 sbc.position(0L);
 169                 write(sbc, "there");
 170             }
 171 
 172             // check file
 173             try (Scanner s = new Scanner(file)) {
 174                 String line = s.nextLine();
 175                 if (!line.equals("hello there"))
 176                     throw new RuntimeException("Unexpected file contents");
 177             }
 178 
 179             // check that read is not allowed
 180             try (SeekableByteChannel sbc = Files.newByteChannel(file, APPEND)) {
 181                 sbc.read(ByteBuffer.allocate(100));
 182             } catch (NonReadableChannelException x) {
 183             }
 184         } finally {
 185             // clean-up
 186             TestUtil.deleteUnchecked(file);
 187         }
 188     }
 189 
 190     // test TRUNCATE_EXISTING option
 191     static void truncateExistingTests(Path dir) throws Exception {
 192         Path file = dir.resolve("foo");
 193         try {
 194             try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, WRITE)) {
 195                 write(sbc, "Have a nice day!");
 196             }
 197 
 198             // re-open with truncate option
 199             // write short message and check
 200             try (SeekableByteChannel sbc = Files.newByteChannel(file, WRITE, TRUNCATE_EXISTING)) {
 201                 write(sbc, "Hello there!");
 202             }
 203             try (Scanner s = new Scanner(file)) {
 204                 String line = s.nextLine();
 205                 if (!line.equals("Hello there!"))
 206                     throw new RuntimeException("Unexpected file contents");
 207             }
 208 
 209             // re-open with create + truncate option
 210             // check file is of size 0L
 211             try (SeekableByteChannel sbc = Files.newByteChannel(file, WRITE, CREATE, TRUNCATE_EXISTING)) {
 212                 long size = ((FileChannel)sbc).size();
 213                 if (size != 0L)
 214                     throw new RuntimeException("File not truncated");
 215             }
 216 
 217         } finally {
 218             // clean-up
 219             TestUtil.deleteUnchecked(file);
 220         }
 221 
 222     }
 223 
 224     // test NOFOLLOW_LINKS option
 225     static void noFollowLinksTests(Path dir) throws Exception {
 226         if (!supportsLinks)
 227             return;
 228         Path file = Files.createFile(dir.resolve("foo"));
 229         try {
 230             // ln -s foo link
 231             Path link = dir.resolve("link");
 232             Files.createSymbolicLink(link, file);
 233 
 234             // open with NOFOLLOW_LINKS option
 235             try {
 236                 Files.newByteChannel(link, READ, LinkOption.NOFOLLOW_LINKS);
 237                 throw new RuntimeException();
 238             } catch (IOException x) {
 239             } finally {
 240                 TestUtil.deleteUnchecked(link);
 241             }
 242 
 243         } finally {
 244             // clean-up
 245             TestUtil.deleteUnchecked(file);
 246         }
 247     }
 248 
 249     // test size/truncate/position methods
 250     static void sizeTruncatePositionTests(Path dir) throws Exception {
 251         Path file = dir.resolve("foo");
 252         try {
 253             try (SeekableByteChannel sbc = Files.newByteChannel(file, CREATE_NEW, READ, WRITE)) {
 254                 if (sbc.size() != 0L)
 255                     throw new RuntimeException("Unexpected size");
 256 
 257                 // check size
 258                 write(sbc, "hello");
 259                 if (sbc.size() != 5L)
 260                     throw new RuntimeException("Unexpected size");
 261 
 262                 // truncate (size and position should change)
 263                 sbc.truncate(4L);
 264                 if (sbc.size() != 4L)
 265                     throw new RuntimeException("Unexpected size");
 266                 if (sbc.position() != 4L)
 267                     throw new RuntimeException("Unexpected position");
 268 
 269                 // truncate (position should not change)
 270                 sbc.position(2L).truncate(3L);
 271                 if (sbc.size() != 3L)
 272                     throw new RuntimeException("Unexpected size");
 273                 if (sbc.position() != 2L)
 274                     throw new RuntimeException("Unexpected position");
 275             }
 276         } finally {
 277             TestUtil.deleteUnchecked(file);
 278         }
 279     }
 280 
 281     // Windows specific options for the use by applications that really want
 282     // to use legacy DOS sharing options
 283     static void dosSharingOptionTests(Path dir) throws Exception {
 284         Path file = Files.createFile(dir.resolve("foo"));
 285         try {
 286             // no sharing
 287             try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_READ,
 288                                                                NOSHARE_WRITE, NOSHARE_DELETE))
 289             {
 290                 try {
 291                     Files.newByteChannel(file, READ);
 292                     throw new RuntimeException("Sharing violation expected");
 293                 } catch (IOException ignore) { }
 294                 try {
 295                     Files.newByteChannel(file, WRITE);
 296                     throw new RuntimeException("Sharing violation expected");
 297                 } catch (IOException ignore) { }
 298                 try {
 299                     Files.delete(file);
 300                     throw new RuntimeException("Sharing violation expected");
 301                 } catch (IOException ignore) { }
 302             }
 303 
 304             // read allowed
 305             try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_WRITE, NOSHARE_DELETE)) {
 306                 Files.newByteChannel(file, READ).close();
 307                 try {
 308                     Files.newByteChannel(file, WRITE);
 309                     throw new RuntimeException("Sharing violation expected");
 310                 } catch (IOException ignore) { }
 311                 try {
 312                     Files.delete(file);
 313                     throw new RuntimeException("Sharing violation expected");
 314                 } catch (IOException ignore) { }
 315             }
 316 
 317             // write allowed
 318             try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_READ, NOSHARE_DELETE)) {
 319                 try {
 320                     Files.newByteChannel(file, READ);
 321                     throw new RuntimeException("Sharing violation expected");
 322                 } catch (IOException ignore) { }
 323                 Files.newByteChannel(file, WRITE).close();
 324                 try {
 325                     Files.delete(file);
 326                     throw new RuntimeException("Sharing violation expected");
 327                 } catch (IOException ignore) { }
 328             }
 329 
 330             // delete allowed
 331             try (SeekableByteChannel ch = Files.newByteChannel(file, READ, NOSHARE_READ, NOSHARE_WRITE)) {
 332                 try {
 333                     Files.newByteChannel(file, READ);
 334                     throw new RuntimeException("Sharing violation expected");
 335                 } catch (IOException ignore) { }
 336                 try {
 337                     Files.newByteChannel(file, WRITE);
 338                     throw new RuntimeException("Sharing violation expected");
 339                 } catch (IOException ignore) { }
 340                 Files.delete(file);
 341             }
 342 
 343         } finally {
 344             TestUtil.deleteUnchecked(file);
 345         }
 346     }
 347 
 348     // invalid combinations of options
 349     static void badCombinations(Path dir) throws Exception {
 350         Path file = dir.resolve("bad");
 351 
 352         try {
 353             Files.newByteChannel(file, READ, APPEND);
 354             throw new RuntimeException("IllegalArgumentException expected");
 355         } catch (IllegalArgumentException x) { }
 356 
 357         try {
 358             Files.newByteChannel(file, WRITE, APPEND, TRUNCATE_EXISTING);
 359             throw new RuntimeException("IllegalArgumentException expected");
 360         } catch (IllegalArgumentException x) { }
 361     }
 362 
 363     // unsupported operations
 364     static void unsupportedOptions(Path dir) throws Exception {
 365         Path file = dir.resolve("bad");
 366 
 367         OpenOption badOption = new OpenOption() { };
 368         try {
 369             Files.newByteChannel(file, badOption);
 370             throw new RuntimeException("UnsupportedOperationException expected");
 371         } catch (UnsupportedOperationException e) { }
 372         try {
 373             Files.newByteChannel(file, READ, WRITE, badOption);
 374             throw new RuntimeException("UnsupportedOperationException expected");
 375         } catch (UnsupportedOperationException e) { }
 376     }
 377 
 378     // null handling
 379     static void nullTests(Path dir) throws Exception {
 380         Path file = dir.resolve("foo");
 381 
 382         try {
 383             OpenOption[] opts = { READ, null };
 384             Files.newByteChannel((Path)null, opts);
 385             throw new RuntimeException("NullPointerException expected");
 386         } catch (NullPointerException x) { }
 387 
 388         try {
 389             Files.newByteChannel(file, (OpenOption[])null);
 390             throw new RuntimeException("NullPointerException expected");
 391         } catch (NullPointerException x) { }
 392 
 393         try {
 394             OpenOption[] opts = { READ, null };
 395             Files.newByteChannel(file, opts);
 396             throw new RuntimeException("NullPointerException expected");
 397         } catch (NullPointerException x) { }
 398 
 399         try {
 400             Files.newByteChannel(file, (Set<OpenOption>)null);
 401             throw new RuntimeException("NullPointerException expected");
 402         } catch (NullPointerException x) { }
 403 
 404         try {
 405             Set<OpenOption> opts = new HashSet<>();
 406             opts.add(READ);
 407             opts.add(null);
 408             Files.newByteChannel(file, opts);
 409             throw new RuntimeException("NullPointerException expected");
 410         } catch (NullPointerException x) { }
 411 
 412         try {
 413             EnumSet<StandardOpenOption> opts = EnumSet.of(READ);
 414             Files.newByteChannel(file, opts, (FileAttribute[])null);
 415             throw new RuntimeException("NullPointerException expected");
 416         } catch (NullPointerException x) { }
 417 
 418         try {
 419             EnumSet<StandardOpenOption> opts = EnumSet.of(READ);
 420             FileAttribute[] attrs = { null };
 421             Files.newByteChannel(file, opts, attrs);
 422             throw new RuntimeException("NullPointerException expected");
 423         } catch (NullPointerException x) { }
 424     }
 425 
 426     static void write(WritableByteChannel wbc, String msg) throws IOException {
 427         ByteBuffer buf = ByteBuffer.wrap(msg.getBytes());
 428         while (buf.hasRemaining())
 429             wbc.write(buf);
 430     }
 431 }