1 /*
   2  * Copyright (c) 2010, 2013, 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 import java.io.*;
  25 import java.nio.*;
  26 import java.nio.channels.*;
  27 import java.nio.file.*;
  28 import java.nio.file.spi.*;
  29 import java.nio.file.attribute.*;
  30 import java.net.*;
  31 import java.util.*;
  32 import java.util.concurrent.TimeUnit;
  33 import java.util.zip.*;
  34 
  35 import static java.nio.file.StandardOpenOption.*;
  36 import static java.nio.file.StandardCopyOption.*;
  37 
  38 /*
  39  * Tests various zipfs operations.
  40  *
  41  * @test
  42  * @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596
  43  *      7157656 8002390 7012868 7012856 8015728 8038500 8040059
  44  * @summary Test Zip filesystem provider
  45  * @run main ZipFSTester
  46  * @run main/othervm/java.security.policy=test.policy ZipFSTester
  47  */
  48 
  49 public class ZipFSTester {
  50 
  51     public static void main(String[] args) throws Throwable {
  52         try (FileSystem fs = newZipFileSystem(
  53                  Paths.get(System.getProperty("test.jdk"), "jre/lib/ext/zipfs.jar"),
  54                  new HashMap<String, Object>()))
  55         {
  56             test0(fs);
  57             test1(fs);
  58             test2(fs);   // more tests
  59         }
  60         testTime(Paths.get(System.getProperty("test.jdk"), "jre/lib/ext/zipfs.jar"));
  61     }
  62 
  63     static void test0(FileSystem fs)
  64         throws Exception
  65     {
  66         List<String> list = new LinkedList<>();
  67         try (ZipFile zf = new ZipFile(fs.toString())) {
  68             Enumeration<? extends ZipEntry> zes = zf.entries();
  69             while (zes.hasMoreElements()) {
  70                 list.add(zes.nextElement().getName());
  71             }
  72             for (String pname : list) {
  73                 Path path = fs.getPath(pname);
  74                 if (!Files.exists(path))
  75                     throw new RuntimeException("path existence check failed!");
  76                 while ((path = path.getParent()) != null) {
  77                     if (!Files.exists(path))
  78                         throw new RuntimeException("parent existence check failed!");
  79                 }
  80             }
  81         }
  82     }
  83 
  84     static void test1(FileSystem fs0)
  85         throws Exception
  86     {
  87         Random rdm = new Random();
  88         // clone a fs and test on it
  89         Path tmpfsPath = getTempPath();
  90         Map<String, Object> env = new HashMap<String, Object>();
  91         env.put("create", "true");
  92         try (FileSystem copy = newZipFileSystem(tmpfsPath, env)) {
  93             z2zcopy(fs0, copy, "/", 0);
  94         }
  95 
  96         try (FileSystem fs = newZipFileSystem(tmpfsPath, new HashMap<String, Object>())) {
  97 
  98             FileSystemProvider provider = fs.provider();
  99             // newFileSystem(path...) should not throw exception
 100             try (FileSystem fsPath = provider.newFileSystem(tmpfsPath, new HashMap<String, Object>())){}
 101             try (FileSystem fsUri = provider.newFileSystem(
 102                      new URI("jar", tmpfsPath.toUri().toString(), null),
 103                      new HashMap<String, Object>()))
 104             {
 105               throw new RuntimeException("newFileSystem(uri...) does not throw exception");
 106             } catch (FileSystemAlreadyExistsException fsaee) {}
 107 
 108             // prepare a src
 109             Path src = getTempPath();
 110             String tmpName = src.toString();
 111             OutputStream os = Files.newOutputStream(src);
 112             byte[] bits = new byte[12345];
 113             rdm.nextBytes(bits);
 114             os.write(bits);
 115             os.close();
 116 
 117             try {
 118                 provider.newFileSystem(new File(System.getProperty("test.src", ".")).toPath(),
 119                                        new HashMap<String, Object>());
 120                 throw new RuntimeException("newFileSystem() opens a directory as zipfs");
 121             } catch (UnsupportedOperationException uoe) {}
 122 
 123             try {
 124                 provider.newFileSystem(src, new HashMap<String, Object>());
 125                 throw new RuntimeException("newFileSystem() opens a non-zip file as zipfs");
 126             } catch (UnsupportedOperationException uoe) {}
 127 
 128 
 129             // copyin
 130             Path dst = getPathWithParents(fs, tmpName);
 131             Files.copy(src, dst);
 132             checkEqual(src, dst);
 133 
 134             // copy
 135             Path dst2 = getPathWithParents(fs, "/xyz" + rdm.nextInt(100) +
 136                                            "/efg" + rdm.nextInt(100) + "/foo.class");
 137             Files.copy(dst, dst2);
 138             //dst.moveTo(dst2);
 139             checkEqual(src, dst2);
 140 
 141             // delete
 142             Files.delete(dst);
 143             if (Files.exists(dst))
 144                 throw new RuntimeException("Failed!");
 145 
 146             // moveout
 147             Path dst3 = Paths.get(tmpName + "_Tmp");
 148             Files.move(dst2, dst3);
 149             checkEqual(src, dst3);
 150             if (Files.exists(dst2))
 151                 throw new RuntimeException("Failed!");
 152 
 153             // copyback + move
 154             Files.copy(dst3, dst);
 155             Path dst4 = getPathWithParents(fs, tmpName + "_Tmp0");
 156             Files.move(dst, dst4);
 157             checkEqual(src, dst4);
 158 
 159             // delete
 160             Files.delete(dst4);
 161             if (Files.exists(dst4))
 162                 throw new RuntimeException("Failed!");
 163             Files.delete(dst3);
 164             if (Files.exists(dst3))
 165                 throw new RuntimeException("Failed!");
 166 
 167             // move (existing entry)
 168             Path dst5 = fs.getPath("META-INF/MANIFEST.MF");
 169             if (Files.exists(dst5)) {
 170                 Path dst6 = fs.getPath("META-INF/MANIFEST.MF_TMP");
 171                 Files.move(dst5, dst6);
 172                 walk(fs.getPath("/"));
 173             }
 174 
 175             // newInputStream on dir
 176             Path parent = dst2.getParent();
 177             try {
 178                 Files.newInputStream(parent);
 179                 throw new RuntimeException("Failed");
 180             } catch (FileSystemException e) {
 181                 e.printStackTrace();    // expected fse
 182             }
 183 
 184             // rmdirs
 185             try {
 186                 rmdirs(parent);
 187             } catch (IOException x) {
 188                 x.printStackTrace();
 189             }
 190 
 191             // newFileChannel() copy in, out and verify via fch
 192             fchCopy(src, dst);    // in
 193             checkEqual(src, dst);
 194             Path tmp = Paths.get(tmpName + "_Tmp");
 195             fchCopy(dst, tmp);   //  out
 196             checkEqual(src, tmp);
 197             Files.delete(tmp);
 198 
 199             // test channels
 200             channel(fs, dst);
 201             Files.delete(dst);
 202             Files.delete(src);
 203         } finally {
 204             if (Files.exists(tmpfsPath))
 205                 Files.delete(tmpfsPath);
 206         }
 207     }
 208 
 209     static void test2(FileSystem fs) throws Exception {
 210 
 211         Path fs1Path = getTempPath();
 212         Path fs2Path = getTempPath();
 213         Path fs3Path = getTempPath();
 214 
 215         // create a new filesystem, copy everything from fs
 216         Map<String, Object> env = new HashMap<String, Object>();
 217         env.put("create", "true");
 218         FileSystem fs0 = newZipFileSystem(fs1Path, env);
 219 
 220         final FileSystem fs2 = newZipFileSystem(fs2Path, env);
 221         final FileSystem fs3 = newZipFileSystem(fs3Path, env);
 222 
 223         System.out.println("copy src: fs -> fs0...");
 224         z2zcopy(fs, fs0, "/", 0);   // copy fs -> fs1
 225         fs0.close();                // dump to file
 226 
 227         System.out.println("open fs0 as fs1");
 228         env = new HashMap<String, Object>();
 229         final FileSystem fs1 = newZipFileSystem(fs1Path, env);
 230 
 231         System.out.println("listing...");
 232         final ArrayList<String> files = new ArrayList<>();
 233         final ArrayList<String> dirs = new ArrayList<>();
 234         list(fs1.getPath("/"), files, dirs);
 235 
 236         Thread t0 = new Thread(new Runnable() {
 237             public void run() {
 238                 List<String> list = new ArrayList<>(dirs);
 239                 Collections.shuffle(list);
 240                 for (String path : list) {
 241                     try {
 242                         z2zcopy(fs1, fs2, path, 0);
 243                     } catch (Exception x) {
 244                         x.printStackTrace();
 245                     }
 246                 }
 247             }
 248 
 249         });
 250 
 251         Thread t1 = new Thread(new Runnable() {
 252             public void run() {
 253                 List<String> list = new ArrayList<>(dirs);
 254                 Collections.shuffle(list);
 255                 for (String path : list) {
 256                     try {
 257                         z2zcopy(fs1, fs2, path, 1);
 258                     } catch (Exception x) {
 259                         x.printStackTrace();
 260                     }
 261                 }
 262             }
 263 
 264         });
 265 
 266         Thread t2 = new Thread(new Runnable() {
 267             public void run() {
 268                 List<String> list = new ArrayList<>(dirs);
 269                 Collections.shuffle(list);
 270                 for (String path : list) {
 271                     try {
 272                         z2zcopy(fs1, fs2, path, 2);
 273                     } catch (Exception x) {
 274                         x.printStackTrace();
 275                     }
 276                 }
 277             }
 278 
 279         });
 280 
 281         Thread t3 = new Thread(new Runnable() {
 282             public void run() {
 283                 List<String> list = new ArrayList<>(files);
 284                 Collections.shuffle(list);
 285                 while (!list.isEmpty()) {
 286                     Iterator<String> itr = list.iterator();
 287                     while (itr.hasNext()) {
 288                         String path = itr.next();
 289                         try {
 290                             if (Files.exists(fs2.getPath(path))) {
 291                                 z2zmove(fs2, fs3, path);
 292                                 itr.remove();
 293                             }
 294                         } catch (FileAlreadyExistsException x){
 295                             itr.remove();
 296                         } catch (Exception x) {
 297                             x.printStackTrace();
 298                         }
 299                     }
 300                 }
 301             }
 302 
 303         });
 304 
 305         System.out.println("copying/removing...");
 306         t0.start(); t1.start(); t2.start(); t3.start();
 307         t0.join(); t1.join(); t2.join(); t3.join();
 308 
 309         System.out.println("closing: fs1, fs2");
 310         fs1.close();
 311         fs2.close();
 312 
 313         int failed = 0;
 314         System.out.println("checkEqual: fs vs fs3");
 315         for (String path : files) {
 316             try {
 317                 checkEqual(fs.getPath(path), fs3.getPath(path));
 318             } catch (IOException x) {
 319                 //x.printStackTrace();
 320                 failed++;
 321             }
 322         }
 323         System.out.println("closing: fs3");
 324         fs3.close();
 325 
 326         System.out.println("opening: fs3 as fs4");
 327         FileSystem fs4 = newZipFileSystem(fs3Path, env);
 328 
 329 
 330         ArrayList<String> files2 = new ArrayList<>();
 331         ArrayList<String> dirs2 = new ArrayList<>();
 332         list(fs4.getPath("/"), files2, dirs2);
 333 
 334         System.out.println("checkEqual: fs vs fs4");
 335         for (String path : files2) {
 336             checkEqual(fs.getPath(path), fs4.getPath(path));
 337         }
 338         System.out.println("walking: fs4");
 339         walk(fs4.getPath("/"));
 340         System.out.println("closing: fs4");
 341         fs4.close();
 342         System.out.printf("failed=%d%n", failed);
 343 
 344         Files.delete(fs1Path);
 345         Files.delete(fs2Path);
 346         Files.delete(fs3Path);
 347     }
 348 
 349     // test file stamp
 350     static void testTime(Path src) throws Exception {
 351         BasicFileAttributes attrs = Files
 352                         .getFileAttributeView(src, BasicFileAttributeView.class)
 353                         .readAttributes();
 354         // create a new filesystem, copy this file into it
 355         Map<String, Object> env = new HashMap<String, Object>();
 356         env.put("create", "true");
 357         Path fsPath = getTempPath();
 358         FileSystem fs = newZipFileSystem(fsPath, env);
 359 
 360         System.out.println("test copy with timestamps...");
 361         // copyin
 362         Path dst = getPathWithParents(fs, "me");
 363         Files.copy(src, dst, COPY_ATTRIBUTES);
 364         checkEqual(src, dst);
 365         System.out.println("mtime: " + attrs.lastModifiedTime());
 366         System.out.println("ctime: " + attrs.creationTime());
 367         System.out.println("atime: " + attrs.lastAccessTime());
 368         System.out.println(" ==============>");
 369         BasicFileAttributes dstAttrs = Files
 370                         .getFileAttributeView(dst, BasicFileAttributeView.class)
 371                         .readAttributes();
 372         System.out.println("mtime: " + dstAttrs.lastModifiedTime());
 373         System.out.println("ctime: " + dstAttrs.creationTime());
 374         System.out.println("atime: " + dstAttrs.lastAccessTime());
 375 
 376         // 1-second granularity
 377         if (attrs.lastModifiedTime().to(TimeUnit.SECONDS) !=
 378             dstAttrs.lastModifiedTime().to(TimeUnit.SECONDS) ||
 379             attrs.lastAccessTime().to(TimeUnit.SECONDS) !=
 380             dstAttrs.lastAccessTime().to(TimeUnit.SECONDS) ||
 381             attrs.creationTime().to(TimeUnit.SECONDS) !=
 382             dstAttrs.creationTime().to(TimeUnit.SECONDS)) {
 383             throw new RuntimeException("Timestamp Copy Failed!");
 384         }
 385         Files.delete(fsPath);
 386     }
 387 
 388     private static FileSystem newZipFileSystem(Path path, Map<String, ?> env)
 389         throws Exception
 390     {
 391         return FileSystems.newFileSystem(
 392             new URI("jar", path.toUri().toString(), null), env, null);
 393     }
 394 
 395     private static Path getTempPath() throws IOException
 396     {
 397         File tmp = File.createTempFile("testzipfs_", "zip");
 398         tmp.delete();    // we need a clean path, no file
 399         return tmp.toPath();
 400     }
 401 
 402     private static void list(Path path, List<String> files, List<String> dirs )
 403         throws IOException
 404     {
 405         if (Files.isDirectory(path)) {
 406             try (DirectoryStream<Path> ds = Files.newDirectoryStream(path)) {
 407                 for (Path child : ds)
 408                     list(child, files, dirs);
 409             }
 410             dirs.add(path.toString());
 411         } else {
 412             files.add(path.toString());
 413         }
 414     }
 415 
 416     private static void z2zcopy(FileSystem src, FileSystem dst, String path,
 417                                 int method)
 418         throws IOException
 419     {
 420         Path srcPath = src.getPath(path);
 421         Path dstPath = dst.getPath(path);
 422 
 423         if (Files.isDirectory(srcPath)) {
 424             if (!Files.exists(dstPath)) {
 425                 try {
 426                     mkdirs(dstPath);
 427                 } catch (FileAlreadyExistsException x) {}
 428             }
 429             try (DirectoryStream<Path> ds = Files.newDirectoryStream(srcPath)) {
 430                 for (Path child : ds) {
 431                     z2zcopy(src, dst,
 432                            path + (path.endsWith("/")?"":"/") + child.getFileName(),
 433                            method);
 434                 }
 435             }
 436         } else {
 437             try {
 438                 if (Files.exists(dstPath))
 439                     return;
 440                 switch (method) {
 441                 case 0:
 442                     Files.copy(srcPath, dstPath);
 443                     break;
 444                 case 1:
 445                     chCopy(srcPath, dstPath);
 446                     break;
 447                 case 2:
 448                     //fchCopy(srcPath, dstPath);
 449                     streamCopy(srcPath, dstPath);
 450                     break;
 451                 }
 452             } catch (FileAlreadyExistsException x) {}
 453         }
 454     }
 455 
 456     private static void z2zmove(FileSystem src, FileSystem dst, String path)
 457         throws IOException
 458     {
 459         Path srcPath = src.getPath(path);
 460         Path dstPath = dst.getPath(path);
 461 
 462         if (Files.isDirectory(srcPath)) {
 463             if (!Files.exists(dstPath))
 464                 mkdirs(dstPath);
 465             try (DirectoryStream<Path> ds = Files.newDirectoryStream(srcPath)) {
 466                 for (Path child : ds) {
 467                     z2zmove(src, dst,
 468                             path + (path.endsWith("/")?"":"/") + child.getFileName());
 469                 }
 470             }
 471         } else {
 472             //System.out.println("moving..." + path);
 473             Path parent = dstPath.getParent();
 474             if (parent != null && Files.notExists(parent))
 475                 mkdirs(parent);
 476             Files.move(srcPath, dstPath);
 477         }
 478     }
 479 
 480     private static void walk(Path path) throws IOException
 481     {
 482         Files.walkFileTree(
 483             path,
 484             new SimpleFileVisitor<Path>() {
 485                 private int indent = 0;
 486                 private void indent() {
 487                     int n = 0;
 488                     while (n++ < indent)
 489                         System.out.printf(" ");
 490                 }
 491 
 492                 @Override
 493                 public FileVisitResult visitFile(Path file,
 494                                                  BasicFileAttributes attrs)
 495                 {
 496                     indent();
 497                     System.out.printf("%s%n", file.getFileName().toString());
 498                     return FileVisitResult.CONTINUE;
 499                 }
 500 
 501                 @Override
 502                 public FileVisitResult preVisitDirectory(Path dir,
 503                                                          BasicFileAttributes attrs)
 504                 {
 505                     indent();
 506                     System.out.printf("[%s]%n", dir.toString());
 507                     indent += 2;
 508                     return FileVisitResult.CONTINUE;
 509                 }
 510 
 511                 @Override
 512                 public FileVisitResult postVisitDirectory(Path dir,
 513                                                           IOException ioe)
 514                     throws IOException
 515                 {
 516                     indent -= 2;
 517                     return FileVisitResult.CONTINUE;
 518                 }
 519         });
 520     }
 521 
 522     private static void mkdirs(Path path) throws IOException {
 523         if (Files.exists(path))
 524             return;
 525         path = path.toAbsolutePath();
 526         Path parent = path.getParent();
 527         if (parent != null) {
 528             if (Files.notExists(parent))
 529                 mkdirs(parent);
 530         }
 531         Files.createDirectory(path);
 532     }
 533 
 534     private static void rmdirs(Path path) throws IOException {
 535         while (path != null && path.getNameCount() != 0) {
 536             Files.delete(path);
 537             path = path.getParent();
 538         }
 539     }
 540 
 541     // check the content of two paths are equal
 542     private static void checkEqual(Path src, Path dst) throws IOException
 543     {
 544         //System.out.printf("checking <%s> vs <%s>...%n",
 545         //                  src.toString(), dst.toString());
 546 
 547         //streams
 548         byte[] bufSrc = new byte[8192];
 549         byte[] bufDst = new byte[8192];
 550         try (InputStream isSrc = Files.newInputStream(src);
 551              InputStream isDst = Files.newInputStream(dst))
 552         {
 553             int nSrc = 0;
 554             while ((nSrc = isSrc.read(bufSrc)) != -1) {
 555                 int nDst = 0;
 556                 while (nDst < nSrc) {
 557                     int n = isDst.read(bufDst, nDst, nSrc - nDst);
 558                     if (n == -1) {
 559                         System.out.printf("checking <%s> vs <%s>...%n",
 560                                           src.toString(), dst.toString());
 561                         throw new RuntimeException("CHECK FAILED!");
 562                     }
 563                     nDst += n;
 564                 }
 565                 while (--nSrc >= 0) {
 566                     if (bufSrc[nSrc] != bufDst[nSrc]) {
 567                         System.out.printf("checking <%s> vs <%s>...%n",
 568                                           src.toString(), dst.toString());
 569                         throw new RuntimeException("CHECK FAILED!");
 570                     }
 571                     nSrc--;
 572                 }
 573             }
 574         }
 575 
 576         // channels
 577         try (SeekableByteChannel chSrc = Files.newByteChannel(src);
 578              SeekableByteChannel chDst = Files.newByteChannel(dst))
 579         {
 580             if (chSrc.size() != chDst.size()) {
 581                 System.out.printf("src[%s].size=%d, dst[%s].size=%d%n",
 582                                   chSrc.toString(), chSrc.size(),
 583                                   chDst.toString(), chDst.size());
 584                 throw new RuntimeException("CHECK FAILED!");
 585             }
 586             ByteBuffer bbSrc = ByteBuffer.allocate(8192);
 587             ByteBuffer bbDst = ByteBuffer.allocate(8192);
 588 
 589             int nSrc = 0;
 590             while ((nSrc = chSrc.read(bbSrc)) != -1) {
 591                 int nDst = chDst.read(bbDst);
 592                 if (nSrc != nDst) {
 593                     System.out.printf("checking <%s> vs <%s>...%n",
 594                                       src.toString(), dst.toString());
 595                     throw new RuntimeException("CHECK FAILED!");
 596                 }
 597                 while (--nSrc >= 0) {
 598                     if (bbSrc.get(nSrc) != bbDst.get(nSrc)) {
 599                         System.out.printf("checking <%s> vs <%s>...%n",
 600                                           src.toString(), dst.toString());
 601                         throw new RuntimeException("CHECK FAILED!");
 602                     }
 603                     nSrc--;
 604                 }
 605                 bbSrc.flip();
 606                 bbDst.flip();
 607             }
 608 
 609             // Check if source read position is at the end
 610             if (chSrc.position() != chSrc.size()) {
 611                 System.out.printf("src[%s]: size=%d, position=%d%n",
 612                                   chSrc.toString(), chSrc.size(), chSrc.position());
 613                 throw new RuntimeException("CHECK FAILED!");
 614             }
 615 
 616             // Check if destination read position is at the end
 617             if (chDst.position() != chDst.size()) {
 618                 System.out.printf("dst[%s]: size=%d, position=%d%n",
 619                                   chDst.toString(), chDst.size(), chDst.position());
 620                 throw new RuntimeException("CHECK FAILED!");
 621             }
 622         } catch (IOException x) {
 623             x.printStackTrace();
 624         }
 625     }
 626 
 627     private static void fchCopy(Path src, Path dst) throws IOException
 628     {
 629         Set<OpenOption> read = new HashSet<>();
 630         read.add(READ);
 631         Set<OpenOption> openwrite = new HashSet<>();
 632         openwrite.add(CREATE_NEW);
 633         openwrite.add(WRITE);
 634 
 635         try (FileChannel srcFc = src.getFileSystem()
 636                                     .provider()
 637                                     .newFileChannel(src, read);
 638              FileChannel dstFc = dst.getFileSystem()
 639                                     .provider()
 640                                     .newFileChannel(dst, openwrite))
 641         {
 642             ByteBuffer bb = ByteBuffer.allocate(8192);
 643             while (srcFc.read(bb) >= 0) {
 644                 bb.flip();
 645                 dstFc.write(bb);
 646                 bb.clear();
 647             }
 648         }
 649     }
 650 
 651     private static void chCopy(Path src, Path dst) throws IOException
 652     {
 653         Set<OpenOption> read = new HashSet<>();
 654         read.add(READ);
 655         Set<OpenOption> openwrite = new HashSet<>();
 656         openwrite.add(CREATE_NEW);
 657         openwrite.add(WRITE);
 658 
 659         try (SeekableByteChannel srcCh = Files.newByteChannel(src, read);
 660              SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite))
 661         {
 662 
 663             ByteBuffer bb = ByteBuffer.allocate(8192);
 664             while (srcCh.read(bb) >= 0) {
 665                 bb.flip();
 666                 dstCh.write(bb);
 667                 bb.clear();
 668             }
 669 
 670             // Check if source read position is at the end
 671             if (srcCh.position() != srcCh.size()) {
 672                 System.out.printf("src[%s]: size=%d, position=%d%n",
 673                                   srcCh.toString(), srcCh.size(), srcCh.position());
 674                 throw new RuntimeException("CHECK FAILED!");
 675             }
 676 
 677             // Check if destination write position is at the end
 678             if (dstCh.position() != dstCh.size()) {
 679                 System.out.printf("dst[%s]: size=%d, position=%d%n",
 680                                   dstCh.toString(), dstCh.size(), dstCh.position());
 681                 throw new RuntimeException("CHECK FAILED!");
 682             }
 683         }
 684     }
 685 
 686     private static void streamCopy(Path src, Path dst) throws IOException
 687     {
 688         byte[] buf = new byte[8192];
 689         try (InputStream isSrc = Files.newInputStream(src);
 690              OutputStream osDst = Files.newOutputStream(dst))
 691         {
 692             int n = 0;
 693             while ((n = isSrc.read(buf)) != -1) {
 694                 osDst.write(buf, 0, n);
 695             }
 696         }
 697     }
 698 
 699     static void channel(FileSystem fs, Path path)
 700         throws Exception
 701     {
 702         System.out.println("test ByteChannel...");
 703         Set<OpenOption> read = new HashSet<>();
 704         read.add(READ);
 705         int n = 0;
 706         ByteBuffer bb = null;
 707         ByteBuffer bb2 = null;
 708         int N = 120;
 709 
 710         try (SeekableByteChannel sbc = Files.newByteChannel(path)) {
 711             System.out.printf("   sbc[0]: pos=%d, size=%d%n", sbc.position(), sbc.size());
 712             if (sbc.position() != 0) {
 713                 throw new RuntimeException("CHECK FAILED!");
 714             }
 715 
 716             bb = ByteBuffer.allocate((int)sbc.size());
 717             n = sbc.read(bb);
 718             System.out.printf("   sbc[1]: read=%d, pos=%d, size=%d%n",
 719                               n, sbc.position(), sbc.size());
 720             if (sbc.position() != sbc.size()) {
 721                 throw new RuntimeException("CHECK FAILED!");
 722             }
 723             bb2 = ByteBuffer.allocate((int)sbc.size());
 724         }
 725 
 726         // sbc.position(pos) is not supported in current version
 727         // try the FileChannel
 728         try (SeekableByteChannel sbc = fs.provider().newFileChannel(path, read)) {
 729             sbc.position(N);
 730             System.out.printf("   sbc[2]: pos=%d, size=%d%n",
 731                               sbc.position(), sbc.size());
 732             if (sbc.position() != N) {
 733                 throw new RuntimeException("CHECK FAILED!");
 734             }
 735             bb2.limit(100);
 736             n = sbc.read(bb2);
 737             System.out.printf("   sbc[3]: read=%d, pos=%d, size=%d%n",
 738                               n, sbc.position(), sbc.size());
 739             if (n < 0 || sbc.position() != (N + n)) {
 740                 throw new RuntimeException("CHECK FAILED!");
 741             }
 742             System.out.printf("   sbc[4]: bb[%d]=%d, bb1[0]=%d%n",
 743                               N, bb.get(N) & 0xff, bb2.get(0) & 0xff);
 744         }
 745     }
 746 
 747     // create parents if does not exist
 748     static Path getPathWithParents(FileSystem fs, String name)
 749         throws Exception
 750     {
 751         Path path = fs.getPath(name);
 752         Path parent = path.getParent();
 753         if (parent != null && Files.notExists(parent))
 754             mkdirs(parent);
 755         return path;
 756     }
 757 }