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