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