View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.tar;
21  
22  import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
23  import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
24  import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
25  import org.apache.commons.compress.utils.IOUtils;
26  import org.waarp.common.file.FileUtils;
27  import org.waarp.common.logging.SysErrLogger;
28  
29  import java.io.File;
30  import java.io.FileInputStream;
31  import java.io.FileNotFoundException;
32  import java.io.FileOutputStream;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.io.OutputStream;
36  import java.util.ArrayList;
37  import java.util.List;
38  
39  /**
40   * TAR support
41   */
42  public final class TarUtility {
43    private static final File[] FILE_0_LENGTH = {};
44  
45    private TarUtility() {
46    }
47  
48    /**
49     * Create a new Tar from a root directory
50     *
51     * @param directory the base directory
52     * @param filename the output filename
53     * @param absolute store absolute filepath (from directory) or only
54     *     filename
55     *
56     * @return True if OK
57     */
58    public static boolean createTarFromDirectory(final String directory,
59                                                 final String filename,
60                                                 final boolean absolute) {
61      final File rootDir = new File(directory);
62      final File saveFile = new File(filename);
63      // recursive call
64      final TarArchiveOutputStream taos;
65      try {
66        taos = new TarArchiveOutputStream(new FileOutputStream(saveFile));
67      } catch (final FileNotFoundException e) {
68        return false;
69      }
70      taos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
71      try {
72        recurseFiles(rootDir, rootDir, taos, absolute);
73      } catch (final IOException e2) {
74        FileUtils.close(taos);
75        return false;
76      }
77      try {
78        taos.finish();
79      } catch (final IOException e1) {
80        // ignore
81      }
82      FileUtils.close(taos);
83      return true;
84    }
85  
86    /**
87     * Recursive traversal to add files
88     *
89     * @param root
90     * @param file
91     * @param taos
92     * @param absolute
93     *
94     * @throws IOException
95     */
96    private static void recurseFiles(final File root, final File file,
97                                     final TarArchiveOutputStream taos,
98                                     final boolean absolute) throws IOException {
99      if (file.isDirectory()) {
100       // recursive call
101       final File[] files = file.listFiles();
102       for (final File file2 : files) {
103         recurseFiles(root, file2, taos, absolute);
104       }
105     } else if (!file.getName().endsWith(".tar") &&
106                !file.getName().endsWith(".TAR")) {
107       final String filename;
108       if (absolute) {
109         filename =
110             file.getAbsolutePath().substring(root.getAbsolutePath().length());
111       } else {
112         filename = file.getName();
113       }
114       final TarArchiveEntry tae = new TarArchiveEntry(filename);
115       tae.setSize(file.length());
116       taos.putArchiveEntry(tae);
117       final FileInputStream fis = new FileInputStream(file);
118       IOUtils.copy(fis, taos);
119       taos.closeArchiveEntry();
120     }
121   }
122 
123   /**
124    * Create a new Tar from a list of Files (only name of files will be used)
125    *
126    * @param files list of files to add
127    * @param filename the output filename
128    *
129    * @return True if OK
130    */
131   public static boolean createTarFromFiles(final List<File> files,
132                                            final String filename) {
133     return createTarFromFiles(files.toArray(FILE_0_LENGTH), filename);
134   }
135 
136   /**
137    * Create a new Tar from an array of Files (only name of files will be used)
138    *
139    * @param files array of files to add
140    * @param filename the output filename
141    *
142    * @return True if OK
143    */
144   public static boolean createTarFromFiles(final File[] files,
145                                            final String filename) {
146     final File saveFile = new File(filename);
147     // recursive call
148     final TarArchiveOutputStream taos;
149     try {
150       taos = new TarArchiveOutputStream(new FileOutputStream(saveFile));
151     } catch (final FileNotFoundException e) {
152       return false;
153     }
154     taos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
155     for (final File file : files) {
156       try {
157         addFile(file, taos);
158       } catch (final IOException e) {
159         FileUtils.close(taos);
160         return false;
161       }
162     }
163     try {
164       taos.finish();
165     } catch (final IOException e1) {
166       // ignore
167     }
168     FileUtils.close(taos);
169     return true;
170   }
171 
172   /**
173    * Recursive traversal to add files
174    *
175    * @param file
176    * @param taos
177    *
178    * @throws IOException
179    */
180   private static void addFile(final File file,
181                               final TarArchiveOutputStream taos)
182       throws IOException {
183     final String filename;
184     filename = file.getName();
185     final TarArchiveEntry tae = new TarArchiveEntry(filename);
186     tae.setSize(file.length());
187     taos.putArchiveEntry(tae);
188     final FileInputStream fis = new FileInputStream(file);
189     IOUtils.copy(fis, taos);
190     taos.closeArchiveEntry();
191   }
192 
193   /**
194    * Extract all files from Tar into the specified directory
195    *
196    * @param tarFile
197    * @param directory
198    *
199    * @return the list of extracted filenames
200    *
201    * @throws IOException
202    */
203   public static List<String> unTar(final File tarFile, final File directory)
204       throws IOException {
205     final List<String> result = new ArrayList<String>();
206     final InputStream inputStream = new FileInputStream(tarFile);
207     final TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
208     try {
209       TarArchiveEntry entry = in.getNextTarEntry();
210       while (entry != null) {
211         if (entry.isDirectory()) {
212           entry = in.getNextTarEntry();
213           continue;
214         }
215         final File curfile = new File(directory, entry.getName());
216         final File parent = curfile.getParentFile();
217         if (!parent.exists()) {
218           parent.mkdirs();//NOSONAR
219         }
220         final OutputStream out = new FileOutputStream(curfile);
221         try {
222           IOUtils.copy(in, out);
223         } finally {
224           FileUtils.close(out);
225         }
226         result.add(entry.getName());
227         entry = in.getNextTarEntry();
228       }
229     } finally {
230       FileUtils.close(in);
231     }
232     return result;
233   }
234 
235   public static void main(final String[] args) {
236     if (args.length < 3) {
237       SysErrLogger.FAKE_LOGGER.syserr("You need to provide 3 arguments:\n" +
238                                       "   option filedest.tar \"source\"\n" +
239                                       "   where option=1 means untar and source is a directory\n" +
240                                       "   option=2 means tar and source is a directory\n" +
241                                       "   option=3 means tar and source is a list of files comma separated");
242       System.exit(1);//NOSONAR
243     }
244     final int option = Integer.parseInt(args[0]);
245     final String tarfile = args[1];
246     final String tarsource = args[2];
247     final String[] tarfiles;
248     if (option == 3) {
249       tarfiles = args[2].split(",");
250       final File[] files = new File[tarfiles.length];
251       for (int i = 0; i < tarfiles.length; i++) {
252         files[i] = new File(tarfiles[i]);
253       }
254       if (createTarFromFiles(files, tarfile)) {
255         SysErrLogger.FAKE_LOGGER.sysout("TAR OK from multiple files");
256       } else {
257         SysErrLogger.FAKE_LOGGER.syserr("TAR KO from multiple files");
258       }
259     } else if (option == 2) {
260       if (createTarFromDirectory(tarsource, tarfile, false)) {
261         SysErrLogger.FAKE_LOGGER.sysout("TAR OK from directory");
262       } else {
263         SysErrLogger.FAKE_LOGGER.syserr("TAR KO from directory");
264       }
265     } else if (option == 1) {
266       final File tarFile = new File(tarfile);
267       final File directory = new File(tarsource);
268       List<String> result = null;
269       try {
270         result = unTar(tarFile, directory);
271       } catch (final IOException e) {
272         SysErrLogger.FAKE_LOGGER.syserr(e);
273       }
274       if (result == null || result.isEmpty()) {
275         SysErrLogger.FAKE_LOGGER.syserr("UNTAR KO from directory");
276       } else {
277         for (final String string : result) {
278           SysErrLogger.FAKE_LOGGER.sysout("File: " + string);
279         }
280       }
281     }
282 
283   }
284 }