1/*
2 * Copyright (c) 2010, 2014, 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
24import java.io.*;
25import java.nio.*;
26import java.nio.channels.*;
27import java.nio.file.*;
28import java.nio.file.spi.*;
29import java.nio.file.attribute.*;
30import java.net.*;
31import java.text.DateFormat;
32import java.text.SimpleDateFormat;
33import java.util.*;
34
35import static java.nio.file.StandardOpenOption.*;
36import static java.nio.file.StandardCopyOption.*;
37
38/*
39 * ZipFileSystem usage demo
40 *
41 * java Demo action ZipfileName [...]
42 *
43 * @author Xueming Shen
44 */
45
46public class Demo {
47
48    static enum Action {
49        rename,          // <java Demo rename zipfile src dst>
50                         // rename entry src to dst inside zipfile
51
52        movein,          // <java Demo movein zipfile src dst>
53                         // move an external src file into zipfile
54                         // as entry dst
55
56        moveout,         // <java Demo moveout zipfile src dst>
57                         // move a zipfile entry src out to dst
58
59        copy,            // <java Demo copy zipfile src dst>
60                         // copy entry src to dst inside zipfile
61
62        copyin,          // <java Demo copyin zipfile src dst>
63                         // copy an external src file into zipfile
64                         // as entry dst
65
66        copyin_attrs,    // <java Demo copyin_attrs zipfile src dst>
67                         // copy an external src file into zipfile
68                         // as entry dst, with attributes (timestamp)
69
70        copyout,         // <java Demo copyout zipfile src dst>
71                         // copy zipfile entry src" out to file dst
72
73        copyout_attrs,   // <java Demo copyout_attrs zipfile src dst>
74
75        zzmove,          // <java Demo zzmove zfsrc zfdst path>
76                         // move entry path/dir from zfsrc to zfdst
77
78        zzcopy,          // <java Demo zzcopy zfsrc zfdst path>
79                         // copy path from zipfile zfsrc to zipfile
80                         // zfdst
81
82        attrs,           // <java Demo attrs zipfile path>
83                         // printout the attributes of entry path
84
85        attrsspace,      // <java Demo attrsspace zipfile path>
86                         // printout the storespace attrs of entry path
87
88        setmtime,        // <java Demo setmtime zipfile "MM/dd/yy-HH:mm:ss" path...>
89                         // set the lastModifiedTime of entry path
90
91        setatime,        // <java Demo setatime zipfile "MM/dd/yy-HH:mm:ss" path...>
92        setctime,        // <java Demo setctime zipfile "MM/dd/yy-HH:mm:ss" path...>
93
94        lsdir,           // <java Demo lsdir zipfile dir>
95                         // list dir's direct child files/dirs
96
97        mkdir,           // <java Demo mkdir zipfile dir>
98
99        mkdirs,          // <java Demo mkdirs zipfile dir>
100
101        rmdirs,          // <java Demo rmdirs zipfile dir>
102
103        list,            // <java Demo list zipfile [dir]>
104                         // recursively list all entries of dir
105                         // via DirectoryStream
106
107        tlist,           // <java Demo tlist zipfile [dir]>
108                         // list with buildDirTree=true
109
110        vlist,           // <java Demo vlist zipfile [dir]>
111                         // recursively verbose list all entries of
112                         // dir via DirectoryStream
113
114        walk,            // <java Demo walk zipfile [dir]>
115                         // recursively walk all entries of dir
116                         // via Files.walkFileTree
117
118        twalk,           // <java Demo twalk zipfile [dir]>
119                         // walk with buildDirTree=true
120
121        extract,         // <java Demo extract zipfile file [...]>
122
123        update,          // <java Demo extract zipfile file [...]>
124
125        delete,          // <java Demo delete zipfile file [...]>
126
127        add,             // <java Demo add zipfile file [...]>
128
129        create,          // <java Demo create zipfile file [...]>
130                         // create a new zipfile if it doesn't exit
131                         // and then add the file(s) into it.
132
133        attrs2,          // <java Demo attrs2 zipfile file [...]>
134                         // test different ways to print attrs
135
136        prof,
137    }
138
139    public static void main(String[] args) throws Throwable {
140        FileSystemProvider provider = getZipFSProvider();
141        if (provider == null) {
142            System.err.println("ZIP filesystem provider is not installed");
143            System.exit(1);
144        }
145
146        Action action = Action.valueOf(args[0]);
147        Map<String, Object> env = env = new HashMap<>();
148        if (action == Action.create)
149            env.put("create", "true");
150        try (FileSystem fs = provider.newFileSystem(Paths.get(args[1]), env)) {
151            Path path, src, dst;
152            switch (action) {
153            case rename:
154                src = fs.getPath(args[2]);
155                dst = fs.getPath(args[3]);
156                Files.move(src, dst);
157                break;
158            case moveout:
159                src = fs.getPath(args[2]);
160                dst = Paths.get(args[3]);
161                Files.move(src, dst);
162                break;
163            case movein:
164                src = Paths.get(args[2]);
165                dst = fs.getPath(args[3]);
166                Files.move(src, dst);
167                break;
168            case copy:
169                src = fs.getPath(args[2]);
170                dst = fs.getPath(args[3]);
171                Files.copy(src, dst);
172                break;
173            case copyout:
174                src = fs.getPath(args[2]);
175                dst = Paths.get(args[3]);
176                Files.copy(src, dst);
177                break;
178            case copyin:
179                src = Paths.get(args[2]);
180                dst = fs.getPath(args[3]);
181                Files.copy(src, dst);
182                break;
183            case copyin_attrs:
184                src = Paths.get(args[2]);
185                dst = fs.getPath(args[3]);
186                Files.copy(src, dst, COPY_ATTRIBUTES);
187                break;
188            case copyout_attrs:
189                src = fs.getPath(args[2]);
190                dst = Paths.get(args[3]);
191                Files.copy(src, dst, COPY_ATTRIBUTES);
192                break;
193            case zzmove:
194                try (FileSystem fs2 = provider.newFileSystem(Paths.get(args[2]), env)) {
195                    z2zmove(fs, fs2, args[3]);
196                }
197                break;
198            case zzcopy:
199                try (FileSystem fs2 = provider.newFileSystem(Paths.get(args[2]), env)) {
200                    z2zcopy(fs, fs2, args[3]);
201                }
202                break;
203            case attrs:
204                for (int i = 2; i < args.length; i++) {
205                    path = fs.getPath(args[i]);
206                    System.out.println(path);
207                    System.out.println(
208                        Files.readAttributes(path, BasicFileAttributes.class).toString());
209                }
210                break;
211            case setmtime:
212                DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
213                Date newDatetime = df.parse(args[2]);
214                for (int i = 3; i < args.length; i++) {
215                    path = fs.getPath(args[i]);
216                    Files.setAttribute(path, "lastModifiedTime",
217                                       FileTime.fromMillis(newDatetime.getTime()));
218                    System.out.println(
219                        Files.readAttributes(path, BasicFileAttributes.class).toString());
220                }
221                break;
222            case setctime:
223                df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
224                newDatetime = df.parse(args[2]);
225                for (int i = 3; i < args.length; i++) {
226                    path = fs.getPath(args[i]);
227                    Files.setAttribute(path, "creationTime",
228                                       FileTime.fromMillis(newDatetime.getTime()));
229                    System.out.println(
230                        Files.readAttributes(path, BasicFileAttributes.class).toString());
231                }
232                break;
233            case setatime:
234                df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
235                newDatetime = df.parse(args[2]);
236                for (int i = 3; i < args.length; i++) {
237                    path = fs.getPath(args[i]);
238                    Files.setAttribute(path, "lastAccessTime",
239                                       FileTime.fromMillis(newDatetime.getTime()));
240                    System.out.println(
241                        Files.readAttributes(path, BasicFileAttributes.class).toString());
242                }
243                break;
244            case attrsspace:
245                path = fs.getPath("/");
246                FileStore fstore = Files.getFileStore(path);
247                System.out.printf("filestore[%s]%n", fstore.name());
248                System.out.printf("    totalSpace: %d%n",
249                                  (Long)fstore.getAttribute("totalSpace"));
250                System.out.printf("   usableSpace: %d%n",
251                                  (Long)fstore.getAttribute("usableSpace"));
252                System.out.printf("  unallocSpace: %d%n",
253                                  (Long)fstore.getAttribute("unallocatedSpace"));
254                break;
255            case list:
256            case tlist:
257                if (args.length < 3)
258                    list(fs.getPath("/"), false);
259                else
260                    list(fs.getPath(args[2]), false);
261                break;
262            case vlist:
263                if (args.length < 3)
264                    list(fs.getPath("/"), true);
265                else
266                    list(fs.getPath(args[2]), true);
267                break;
268            case twalk:
269            case walk:
270                walk(fs.getPath((args.length > 2)? args[2] : "/"));
271                break;
272            case extract:
273                if (args.length == 2) {
274                     extract(fs, "/");
275                } else {
276                    for (int i = 2; i < args.length; i++) {
277                        extract(fs, args[i]);
278                    }
279                }
280                break;
281            case delete:
282                for (int i = 2; i < args.length; i++)
283                    Files.delete(fs.getPath(args[i]));
284                break;
285            case create:
286            case add:
287            case update:
288                for (int i = 2; i < args.length; i++) {
289                    update(fs, args[i]);
290                }
291                break;
292            case lsdir:
293                path = fs.getPath(args[2]);
294                final String fStr = (args.length > 3)?args[3]:"";
295                try (DirectoryStream<Path> ds = Files.newDirectoryStream(path,
296                    new DirectoryStream.Filter<Path>() {
297                        @Override
298                        public boolean accept(Path path) {
299                            return path.toString().contains(fStr);
300                        }
301                    }))
302                {
303                    for (Path p : ds)
304                        System.out.println(p);
305                }
306                break;
307            case mkdir:
308                Files.createDirectory(fs.getPath(args[2]));
309                break;
310            case mkdirs:
311                mkdirs(fs.getPath(args[2]));
312                break;
313            case attrs2:
314                for (int i = 2; i < args.length; i++) {
315                    path = fs.getPath(args[i]);
316                    System.out.printf("%n%s%n", path);
317                    System.out.println("-------(1)---------");
318                    System.out.println(
319                        Files.readAttributes(path, BasicFileAttributes.class).toString());
320                    System.out.println("-------(2)---------");
321                    Map<String, Object> map = Files.readAttributes(path, "zip:*");
322                    for (Map.Entry<String, Object> e : map.entrySet()) {
323                        System.out.printf("    %s : %s%n", e.getKey(), e.getValue());
324                    }
325                    System.out.println("-------(3)---------");
326                    map = Files.readAttributes(path, "size,lastModifiedTime,isDirectory");
327                    for (Map.Entry<String, ?> e : map.entrySet()) {
328                        System.out.printf("    %s : %s%n", e.getKey(), e.getValue());
329                    }
330                }
331                break;
332            case prof:
333                list(fs.getPath("/"), false);
334                while (true) {
335                    Thread.sleep(10000);
336                    //list(fs.getPath("/"), true);
337                    System.out.println("sleeping...");
338                }
339            }
340        } catch (Exception x) {
341            x.printStackTrace();
342        }
343    }
344
345    private static FileSystemProvider getZipFSProvider() {
346        for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
347            if ("jar".equals(provider.getScheme()))
348                return provider;
349        }
350        return null;
351    }
352
353    @SuppressWarnings("unused")
354    /**
355     * Not used in demo, but included for demonstrational purposes.
356     */
357    private static byte[] getBytes(String name) {
358        return name.getBytes();
359    }
360
361    @SuppressWarnings("unused")
362    /**
363     * Not used in demo, but included for demonstrational purposes.
364     */
365    private static String getString(byte[] name) {
366        return new String(name);
367    }
368
369    private static void walk(Path path) throws IOException
370    {
371        Files.walkFileTree(
372            path,
373            new SimpleFileVisitor<Path>() {
374                private int indent = 0;
375                private void indent() {
376                    int n = 0;
377                    while (n++ < indent)
378                        System.out.printf(" ");
379                }
380
381                @Override
382                public FileVisitResult visitFile(Path file,
383                                                 BasicFileAttributes attrs)
384                {
385                    indent();
386                    System.out.printf("%s%n", file.getFileName().toString());
387                    return FileVisitResult.CONTINUE;
388                }
389
390                @Override
391                public FileVisitResult preVisitDirectory(Path dir,
392                                                         BasicFileAttributes attrs)
393                {
394                    indent();
395                    System.out.printf("[%s]%n", dir.toString());
396                    indent += 2;
397                    return FileVisitResult.CONTINUE;
398                }
399
400                @Override
401                public FileVisitResult postVisitDirectory(Path dir,
402                                                          IOException ioe)
403                {
404                    indent -= 2;
405                    return FileVisitResult.CONTINUE;
406                }
407        });
408    }
409
410    private static void update(FileSystem fs, String path) throws Throwable{
411        Path src = FileSystems.getDefault().getPath(path);
412        if (Files.isDirectory(src)) {
413            try (DirectoryStream<Path> ds = Files.newDirectoryStream(src)) {
414                for (Path child : ds)
415                    update(fs, child.toString());
416            }
417        } else {
418            Path dst = fs.getPath(path);
419            Path parent = dst.getParent();
420            if (parent != null && Files.notExists(parent))
421                mkdirs(parent);
422            Files.copy(src, dst, REPLACE_EXISTING);
423        }
424    }
425
426    private static void extract(FileSystem fs, String path) throws Throwable{
427        Path src = fs.getPath(path);
428        if (Files.isDirectory(src)) {
429            try (DirectoryStream<Path> ds = Files.newDirectoryStream(src)) {
430                for (Path child : ds)
431                    extract(fs, child.toString());
432            }
433        } else {
434            if (path.startsWith("/"))
435                path = path.substring(1);
436            Path dst = FileSystems.getDefault().getPath(path);
437            Path parent = dst.getParent();
438            if (Files.notExists(parent))
439                mkdirs(parent);
440            Files.copy(src, dst, REPLACE_EXISTING);
441        }
442    }
443
444    // use DirectoryStream
445    private static void z2zcopy(FileSystem src, FileSystem dst, String path)
446        throws IOException
447    {
448        Path srcPath = src.getPath(path);
449        Path dstPath = dst.getPath(path);
450
451        if (Files.isDirectory(srcPath)) {
452            if (!Files.exists(dstPath)) {
453                try {
454                    mkdirs(dstPath);
455                } catch (FileAlreadyExistsException x) {}
456            }
457            try (DirectoryStream<Path> ds = Files.newDirectoryStream(srcPath)) {
458                for (Path child : ds) {
459                    z2zcopy(src, dst,
460                            path + (path.endsWith("/")?"":"/") + child.getFileName());
461                }
462            }
463        } else {
464            //System.out.println("copying..." + path);
465            Files.copy(srcPath, dstPath);
466        }
467    }
468
469    // use TreeWalk to move
470    private static void z2zmove(FileSystem src, FileSystem dst, String path)
471        throws IOException
472    {
473        final Path srcPath = src.getPath(path).toAbsolutePath();
474        final Path dstPath = dst.getPath(path).toAbsolutePath();
475
476        Files.walkFileTree(srcPath, new SimpleFileVisitor<Path>() {
477
478            @Override
479            public FileVisitResult visitFile(Path file,
480                                            BasicFileAttributes attrs)
481            {
482                Path dst = srcPath.relativize(file);
483                dst = dstPath.resolve(dst);
484                try {
485                    Path parent = dstPath.getParent();
486                    if (parent != null && Files.notExists(parent))
487                        mkdirs(parent);
488                    Files.move(file, dst);
489                } catch (IOException x) {
490                    x.printStackTrace();
491                }
492                return FileVisitResult.CONTINUE;
493            }
494
495            @Override
496            public FileVisitResult preVisitDirectory(Path dir,
497                                                     BasicFileAttributes attrs)
498            {
499                Path dst = srcPath.relativize(dir);
500                dst = dstPath.resolve(dst);
501                try {
502
503                    if (Files.notExists(dst))
504                        mkdirs(dst);
505                } catch (IOException x) {
506                    x.printStackTrace();
507                }
508                return FileVisitResult.CONTINUE;
509            }
510
511            @Override
512            public FileVisitResult postVisitDirectory(Path dir,
513                                                      IOException ioe)
514                throws IOException
515            {
516                try {
517                    Files.delete(dir);
518                } catch (IOException x) {
519                    //x.printStackTrace();
520                }
521                return FileVisitResult.CONTINUE;
522            }
523        });
524
525    }
526
527    private static void mkdirs(Path path) throws IOException {
528        path = path.toAbsolutePath();
529        Path parent = path.getParent();
530        if (parent != null) {
531            if (Files.notExists(parent))
532                mkdirs(parent);
533        }
534        Files.createDirectory(path);
535    }
536
537    @SuppressWarnings("unused")
538    /**
539     * Not used in demo, but included for demonstrational purposes.
540     */
541    private static void rmdirs(Path path) throws IOException {
542        while (path != null && path.getNameCount() != 0) {
543            Files.delete(path);
544            path = path.getParent();
545        }
546    }
547
548    private static void list(Path path, boolean verbose ) throws IOException {
549        if (!"/".equals(path.toString())) {
550           System.out.printf("  %s%n", path.toString());
551           if (verbose)
552                System.out.println(Files.readAttributes(path, BasicFileAttributes.class).toString());
553        }
554        if (Files.notExists(path))
555            return;
556        if (Files.isDirectory(path)) {
557            try (DirectoryStream<Path> ds = Files.newDirectoryStream(path)) {
558                for (Path child : ds)
559                    list(child, verbose);
560            }
561        }
562    }
563
564    @SuppressWarnings("unused")
565    /**
566     * Checks that the content of two paths are equal.
567     * Not used in demo, but included for demonstrational purposes.
568     */
569    private static void checkEqual(Path src, Path dst) throws IOException
570    {
571        //System.out.printf("checking <%s> vs <%s>...%n",
572        //                  src.toString(), dst.toString());
573
574        //streams
575        byte[] bufSrc = new byte[8192];
576        byte[] bufDst = new byte[8192];
577        try (InputStream isSrc = Files.newInputStream(src);
578             InputStream isDst = Files.newInputStream(dst))
579        {
580            int nSrc = 0;
581            while ((nSrc = isSrc.read(bufSrc)) != -1) {
582                int nDst = 0;
583                while (nDst < nSrc) {
584                    int n = isDst.read(bufDst, nDst, nSrc - nDst);
585                    if (n == -1) {
586                        System.out.printf("checking <%s> vs <%s>...%n",
587                                          src.toString(), dst.toString());
588                        throw new RuntimeException("CHECK FAILED!");
589                    }
590                    nDst += n;
591                }
592                while (--nSrc >= 0) {
593                    if (bufSrc[nSrc] != bufDst[nSrc]) {
594                        System.out.printf("checking <%s> vs <%s>...%n",
595                                          src.toString(), dst.toString());
596                        throw new RuntimeException("CHECK FAILED!");
597                    }
598                    nSrc--;
599                }
600            }
601        }
602
603        // channels
604
605        try (SeekableByteChannel chSrc = Files.newByteChannel(src);
606             SeekableByteChannel chDst = Files.newByteChannel(dst))
607        {
608            if (chSrc.size() != chDst.size()) {
609                System.out.printf("src[%s].size=%d, dst[%s].size=%d%n",
610                                  chSrc.toString(), chSrc.size(),
611                                  chDst.toString(), chDst.size());
612                throw new RuntimeException("CHECK FAILED!");
613            }
614            ByteBuffer bbSrc = ByteBuffer.allocate(8192);
615            ByteBuffer bbDst = ByteBuffer.allocate(8192);
616
617            int nSrc = 0;
618            while ((nSrc = chSrc.read(bbSrc)) != -1) {
619                int nDst = chDst.read(bbDst);
620                if (nSrc != nDst) {
621                    System.out.printf("checking <%s> vs <%s>...%n",
622                                      src.toString(), dst.toString());
623                    throw new RuntimeException("CHECK FAILED!");
624                }
625                while (--nSrc >= 0) {
626                    if (bbSrc.get(nSrc) != bbDst.get(nSrc)) {
627                        System.out.printf("checking <%s> vs <%s>...%n",
628                                          src.toString(), dst.toString());
629                        throw new RuntimeException("CHECK FAILED!");
630                    }
631                    nSrc--;
632                }
633                bbSrc.flip();
634                bbDst.flip();
635            }
636        } catch (IOException x) {
637            x.printStackTrace();
638        }
639    }
640
641    private static void fchCopy(Path src, Path dst) throws IOException
642    {
643        Set<OpenOption> read = new HashSet<>();
644        read.add(READ);
645        Set<OpenOption> openwrite = new HashSet<>();
646        openwrite.add(CREATE_NEW);
647        openwrite.add(WRITE);
648
649        try (FileChannel srcFc = src.getFileSystem().provider().newFileChannel(src, read);
650             FileChannel dstFc = dst.getFileSystem().provider().newFileChannel(dst, openwrite))
651        {
652            ByteBuffer bb = ByteBuffer.allocate(8192);
653            while (srcFc.read(bb) >= 0) {
654                bb.flip();
655                dstFc.write(bb);
656                bb.clear();
657            }
658        }
659    }
660
661    private static void chCopy(Path src, Path dst) throws IOException
662    {
663        Set<OpenOption> read = new HashSet<>();
664        read.add(READ);
665        Set<OpenOption> openwrite = new HashSet<>();
666        openwrite.add(CREATE_NEW);
667        openwrite.add(WRITE);
668
669        try (SeekableByteChannel srcCh = Files.newByteChannel(src, read);
670             SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite))
671        {
672            ByteBuffer bb = ByteBuffer.allocate(8192);
673            while (srcCh.read(bb) >= 0) {
674                bb.flip();
675                dstCh.write(bb);
676                bb.clear();
677            }
678        }
679    }
680
681    private static void streamCopy(Path src, Path dst) throws IOException
682    {
683        byte[] buf = new byte[8192];
684        try (InputStream isSrc = Files.newInputStream(src);
685             OutputStream osDst = Files.newOutputStream(dst))
686        {
687            int n = 0;
688            while ((n = isSrc.read(buf)) != -1) {
689                osDst.write(buf, 0, n);
690            }
691        }
692    }
693}
694