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