1 /*
2  * Copyright (c) 2008, 2016, 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 jdk.unsupported
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 
main(String[] args)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
createTests(Path dir)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
appendTests(Path dir)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
truncateExistingTests(Path dir)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
noFollowLinksTests(Path dir)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
sizeTruncatePositionTests(Path dir)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
dosSharingOptionTests(Path dir)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
badCombinations(Path dir)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
unsupportedOptions(Path dir)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
nullTests(Path dir)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 
write(WritableByteChannel wbc, String msg)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 }
433