Example #1
0
  /**
   * Insert a list of files into an archive.
   *
   * <p>This is used by Create and Append to insert new entries into the archive.
   *
   * <p>TODO Allow files to be delete from the filesystem after the archive has been written. If the
   * verify option is set, then the archive must pass verification before the files are deleted.
   *
   * <p>TODO If the verify option is set, the original archive is backed up before operating on it,
   * and verified before exiting. If the archive is bad, the original is restored.
   */
  private void insert(File[] files) throws IOException {
    InputStream in;
    OutputStream out;
    TarOutputStream tout = null;
    TarEntry entry;

    if (mode == TAR_APPEND && archive.exists()) {
      tout = appendTarOutputStream();
    } else {
      createArchive();
      if ((out = openFileWrite(archive, false, false)) == null) {
        fatal(" ", 1);
      }
      if (compress != 0) {
        out = wrapOutputStream(out);
      }
      tout = new TarOutputStream(out);
    }

    // Insert new entries
    for (File file : files) {
      notice(file.getPath());
      entry = new TarEntry(file);
      tout.putNextEntry(entry);

      if (!file.isDirectory()) {
        if ((in = openFileRead(file)) == null) continue;
        processStream(in, tout);
        in.close();
      }
      tout.closeEntry();
    }
    tout.close();
  }
 // 循环遍历目录结构中的文件并添加至tar的输出流
 public static void addFiles(TarOutputStream tout, String folderPath) {
   File srcPath = new File(folderPath);
   int length = srcPath.listFiles().length;
   byte[] buf = new byte[1024]; // 设定读入缓冲区尺寸
   File[] files = srcPath.listFiles();
   try {
     for (int i = 0; i < length; i++) {
       if (files[i].isFile()) {
         System.out.println("file:" + files[i].getName());
         String filename = srcPath.getPath() + File.separator + files[i].getName();
         // 打开需压缩文件作为文件输入流
         FileInputStream fin = new FileInputStream(filename); // filename是文件全路径
         TarEntry tarEn = new TarEntry(files[i]); // 此处必须使用new
         // TarEntry(File
         // file);
         // tarEn.setName(files[i].getName());
         // //此处需重置名称,默认是带全路径的,否则打包后会带全路径
         tout.putNextEntry(tarEn);
         int num;
         while ((num = fin.read(buf)) != -1) {
           tout.write(buf, 0, num);
         }
         tout.closeEntry();
         fin.close();
       } else {
         System.out.println(files[i].getPath());
         addFiles(tout, files[i].getPath());
       }
     }
   } catch (FileNotFoundException e) {
     System.out.println(e);
   } catch (IOException e) {
     System.out.println(e);
   }
 }
  // 生成tar并压缩成tar.gz
  public static void WriteToTarGzip(String folderPath, String targzipFilePath) {
    byte[] buf = new byte[1024]; // 设定读入缓冲区尺寸
    try {
      // 建立压缩文件输出流
      FileOutputStream fout = new FileOutputStream(targzipFilePath);
      // 建立tar压缩输出流
      TarOutputStream tout = new TarOutputStream(fout);
      addFiles(tout, folderPath);
      tout.close();
      fout.close();

      // 建立压缩文件输出流
      FileOutputStream gzFile = new FileOutputStream(targzipFilePath + ".gz");
      // 建立gzip压缩输出流
      GZIPOutputStream gzout = new GZIPOutputStream(gzFile);
      // 打开需压缩文件作为文件输入流
      FileInputStream tarin = new FileInputStream(targzipFilePath); // targzipFilePath是文件全路径
      int len;
      while ((len = tarin.read(buf)) != -1) {
        gzout.write(buf, 0, len);
      }
      gzout.close();
      gzFile.close();
      tarin.close();

    } catch (FileNotFoundException e) {
      System.out.println(e);
    } catch (IOException e) {
      System.out.println(e);
    }

    File tarfile = new File(targzipFilePath);
    tarfile.delete();
  }
 /**
  * Archive a directory.
  *
  * @param source A <code>File</code>.
  * @param target A <code>File</code>.
  * @throws IOException
  */
 public void archive(final File source, final File target, final byte[] buffer)
     throws IOException {
   final TarOutputStream targetStream = newTargetStream(target);
   try {
     targetStream.setLongFileMode(TarOutputStream.LONGFILE_GNU);
     final File[] sourceFileArray = new FileSystem(source).listFiles("/", Boolean.TRUE);
     TarEntry tarEntry;
     InputStream sourceStream;
     for (int i = 0; i < sourceFileArray.length; i++) {
       tarEntry = new TarEntry(sourceFileArray[i]);
       targetStream.putNextEntry(tarEntry);
       try {
         sourceStream = new FileInputStream(sourceFileArray[i]);
         try {
           StreamUtil.copy(sourceStream, targetStream, buffer);
         } finally {
           sourceStream.close();
         }
       } finally {
         targetStream.closeEntry();
       }
     }
   } finally {
     targetStream.close();
   }
 }
  // 不能对每层都包含文件和目录的多层次目录结构打包
  public static void compressedFiles_Gzip(String folderPath, String targzipFilePath) {
    File srcPath = new File(folderPath);
    int length = srcPath.listFiles().length;
    byte[] buf = new byte[1024]; // 设定读入缓冲区尺寸
    File[] files = srcPath.listFiles();
    try {
      File targetFile = new File(targzipFilePath);
      File parent = targetFile.getParentFile();
      if (!parent.exists()) {
        parent.mkdirs();
      }
      // 建立压缩文件输出流
      FileOutputStream fout = new FileOutputStream(targetFile);
      // 建立tar压缩输出流
      TarOutputStream tout = new TarOutputStream(fout);
      for (int i = 0; i < length; i++) {
        String filename = srcPath.getPath() + File.separator + files[i].getName();
        // 打开需压缩文件作为文件输入流
        FileInputStream fin = new FileInputStream(filename); // filename是文件全路径
        TarEntry tarEn = new TarEntry(files[i]); // 此处必须使用new
        // TarEntry(File
        // file);
        // tarEn.setName(files[i].getName());
        // //此处需重置名称,默认是带全路径的,否则打包后会带全路径
        tout.putNextEntry(tarEn);
        int num;
        while ((num = fin.read(buf)) != -1) {
          tout.write(buf, 0, num);
        }
        tout.closeEntry();
        fin.close();
      }

      tout.close();
      fout.close();

      // 建立压缩文件输出流
      FileOutputStream gzFile = new FileOutputStream(targzipFilePath + ".gz");
      // 建立gzip压缩输出流
      GZIPOutputStream gzout = new GZIPOutputStream(gzFile);
      // 打开需压缩文件作为文件输入流
      FileInputStream tarin = new FileInputStream(targzipFilePath); // targzipFilePath是文件全路径
      int len;
      while ((len = tarin.read(buf)) != -1) {
        gzout.write(buf, 0, len);
      }
      gzout.close();
      gzFile.close();
      tarin.close();
      // 因为只要tar.gz文件,所以删除.tar文件
      del(targzipFilePath);
    } catch (FileNotFoundException e) {
      System.out.println(e);
    } catch (IOException e) {
      System.out.println(e);
    }
  }
Example #6
0
 /**
  * Copies an archive to another archive.
  *
  * <p>This is used to set an output stream into position for appending new entries, and to copy
  * entries from another archive into another archive.
  *
  * <p>FIXME does not verify that tin is actually a tar archive (Concat)
  */
 private void copy(TarInputStream tin, TarOutputStream tout) throws IOException {
   TarEntry entry;
   while ((entry = tin.getNextEntry()) != null) {
     tout.putNextEntry(entry);
     tin.copyEntryContents(tout);
     tout.closeEntry();
   }
   tin.close();
 }
Example #7
0
  private static void addEntry(
      final String pName, final String pContent, final TarOutputStream pOutput) throws IOException {
    final byte[] data = pContent.getBytes("UTF-8");

    final TarEntry entry = new TarEntry("./" + pName);
    entry.setSize(data.length);
    entry.setNames("root", "root");

    pOutput.putNextEntry(entry);
    pOutput.write(data);
    pOutput.closeEntry();
  }
Example #8
0
  /**
   * Concatenates a list of archives with this archive.
   *
   * <p>TODO If the verify option is set, the original archive is backed up before operating on it,
   * and verified before exiting. If the archive is bad, the original is restored.
   */
  private void concat(File[] archives) throws IOException {
    InputStream in;
    TarInputStream tin;
    TarOutputStream tout;

    // Setup archive for appending
    tout = appendTarOutputStream();

    // Concatenate new archives
    for (File arch : archives) {
      if ((in = openFileRead(arch)) == null) {
        continue;
      }
      bzip = gzip = false;
      decompress = checkCompressed(arch);
      if (decompress != 0) {
        in = wrapInputStream(in);
      }
      tin = new TarInputStream(in);
      copy(tin, tout);
    }
    tout.close();
  }
Example #9
0
  @Test(timeout = 30000)
  public void testUnTar() throws IOException {
    setupDirs();

    // make a simple tar:
    final File simpleTar = new File(del, FILE);
    OutputStream os = new FileOutputStream(simpleTar);
    TarOutputStream tos = new TarOutputStream(os);
    try {
      TarEntry te = new TarEntry("/bar/foo");
      byte[] data = "some-content".getBytes("UTF-8");
      te.setSize(data.length);
      tos.putNextEntry(te);
      tos.write(data);
      tos.closeEntry();
      tos.flush();
      tos.finish();
    } finally {
      tos.close();
    }

    // successfully untar it into an existing dir:
    FileUtil.unTar(simpleTar, tmp);
    // check result:
    assertTrue(new File(tmp, "/bar/foo").exists());
    assertEquals(12, new File(tmp, "/bar/foo").length());

    final File regularFile = new File(tmp, "QuickBrownFoxJumpsOverTheLazyDog");
    regularFile.createNewFile();
    assertTrue(regularFile.exists());
    try {
      FileUtil.unTar(simpleTar, regularFile);
      assertTrue("An IOException expected.", false);
    } catch (IOException ioe) {
      // okay
    }
  }
Example #10
0
  /**
   * Build the data archive of the deb from the provided DataProducers
   *
   * @param pData
   * @param pOutput
   * @param pChecksums
   * @param pCompression the compression method used for the data file (gzip, bzip2 or anything else
   *     for no compression)
   * @return
   * @throws NoSuchAlgorithmException
   * @throws IOException
   */
  BigInteger buildData(
      final DataProducer[] pData,
      final File pOutput,
      final StringBuffer pChecksums,
      String pCompression)
      throws NoSuchAlgorithmException, IOException {

    OutputStream out = new FileOutputStream(pOutput);
    if ("gzip".equals(pCompression)) {
      out = new GZIPOutputStream(out);
    } else if ("bzip2".equals(pCompression)) {
      out.write("BZ".getBytes());
      out = new CBZip2OutputStream(out);
    }

    final TarOutputStream outputStream = new TarOutputStream(out);
    outputStream.setLongFileMode(TarOutputStream.LONGFILE_GNU);

    final MessageDigest digest = MessageDigest.getInstance("MD5");

    final Total dataSize = new Total();

    final List addedDirectories = new ArrayList();
    final DataConsumer receiver =
        new DataConsumer() {
          public void onEachDir(
              String dirname,
              String linkname,
              String user,
              int uid,
              String group,
              int gid,
              int mode,
              long size)
              throws IOException {
            dirname = fixPath(dirname);

            createParentDirectories((new File(dirname)).getParent(), user, uid, group, gid);

            // The directory passed in explicitly by the caller also gets the passed-in mode.
            // (Unlike
            // the parent directories for now.  See related comments at "int mode =" in
            // createParentDirectories, including about a possible bug.)
            createDirectory(dirname, user, uid, group, gid, mode, 0);

            console.println("dir: " + dirname);
          }

          public void onEachFile(
              InputStream inputStream,
              String filename,
              String linkname,
              String user,
              int uid,
              String group,
              int gid,
              int mode,
              long size)
              throws IOException {
            filename = fixPath(filename);

            createParentDirectories(fixPath(new File(filename).getParent()), user, uid, group, gid);

            TarEntry entry = new TarEntry(filename);

            // FIXME: link is in the constructor
            entry.setUserName(user);
            entry.setUserId(uid);
            entry.setGroupName(group);
            entry.setGroupId(gid);
            entry.setMode(mode);
            entry.setSize(size);

            outputStream.putNextEntry(entry);

            dataSize.add(size);

            digest.reset();

            Utils.copy(inputStream, new DigestOutputStream(outputStream, digest));

            final String md5 = Utils.toHex(digest.digest());

            outputStream.closeEntry();

            console.println(
                "file:"
                    + entry.getName()
                    + " size:"
                    + entry.getSize()
                    + " mode:"
                    + entry.getMode()
                    + " linkname:"
                    + entry.getLinkName()
                    + " username:"******" userid:"
                    + entry.getUserId()
                    + " groupname:"
                    + entry.getGroupName()
                    + " groupid:"
                    + entry.getGroupId()
                    + " modtime:"
                    + entry.getModTime()
                    + " md5: "
                    + md5);

            pChecksums.append(md5).append(" ").append(entry.getName()).append('\n');
          }

          private String fixPath(String path) {
            // If we're receiving directory names from Windows, then we'll convert to use slash
            // This does eliminate the ability to use of a backslash in a directory name on *NIX,
            // but in practice, this is a non-issue
            if (path.indexOf('\\') > -1) {
              path = path.replace('\\', '/');
            }
            // ensure the path is like : ./foo/bar
            if (path.startsWith("/")) {
              path = "." + path;
            } else if (!path.startsWith("./")) {
              path = "./" + path;
            }
            // remove double slashes in order to get unique file/folder names
            path = path.replaceAll("\\/\\/", "\\/");
            return path;
          }

          private void createDirectory(
              String directory, String user, int uid, String group, int gid, int mode, long size)
              throws IOException {
            // All dirs should end with "/" when created, or the test
            // DebAndTaskTestCase.testTarFileSet() thinks its a file
            // and so thinks it has the wrong permission.
            // This consistency also helps when checking if a directory already exists in
            // addedDirectories.

            if (!directory.endsWith("/")) {
              directory += "/";
            }

            if (!addedDirectories.contains(directory)) {
              TarEntry entry = new TarEntry(directory);
              // FIXME: link is in the constructor
              entry.setUserName(user);
              entry.setUserId(uid);
              entry.setGroupName(group);
              entry.setGroupId(gid);
              entry.setMode(mode);
              entry.setSize(size);

              outputStream.putNextEntry(entry);
              outputStream.closeEntry();
              addedDirectories.add(
                  directory); // so addedDirectories consistently have "/" for finding duplicates.
            }
          }

          private void createParentDirectories(
              String dirname, String user, int uid, String group, int gid) throws IOException {
            // Debian packages must have parent directories created
            // before sub-directories or files can be installed.
            // For example, if an entry of ./usr/lib/foo/bar existed
            // in a .deb package, but the ./usr/lib/foo directory didn't
            // exist, the package installation would fail.  The .deb must
            // then have an entry for ./usr/lib/foo and then ./usr/lib/foo/bar

            if (dirname == null) {
              return;
            }

            // The loop below will create entries for all parent directories
            // to ensure that .deb packages will install correctly.
            String[] pathParts = dirname.split("\\/");
            String parentDir = "./";
            for (int i = 1; i < pathParts.length; i++) {
              parentDir += pathParts[i] + "/";
              // Make it so the dirs can be traversed by users.
              // We could instead try something more granular, like setting the directory
              // permission to 'rx' for each of the 3 user/group/other read permissions
              // found on the file being added (ie, only if "other" has read
              // permission on the main node, then add o+rx permission on all the containing
              // directories, same w/ user & group), and then also we'd have to
              // check the parentDirs collection of those already added to
              // see if those permissions need to be similarly updated.  (Note, it hasn't
              // been demonstrated, but there might be a bug if a user specifically
              // requests a directory with certain permissions,
              // that has already been auto-created because it was a parent, and if so, go set
              // the user-requested mode on that directory instead of this automatic one.)
              // But for now, keeping it simple by making every dir a+rx.   Examples are:
              // drw-r----- fs/fs   # what you get with setMode(mode)
              // drwxr-xr-x fs/fs   # Usable. Too loose?
              int mode = TarEntry.DEFAULT_DIR_MODE;

              createDirectory(parentDir, user, uid, group, gid, mode, 0);
            }
          }
        };

    for (int i = 0; i < pData.length; i++) {
      final DataProducer data = pData[i];
      data.produce(receiver);
    }

    outputStream.close();

    console.println("Total size: " + dataSize);

    return dataSize.count;
  }
Example #11
0
  /**
   * Build control archive of the deb
   *
   * @param pControlFiles
   * @param pDataSize
   * @param pChecksums
   * @param pOutput
   * @return
   * @throws FileNotFoundException
   * @throws IOException
   * @throws ParseException
   */
  private PackageDescriptor buildControl(
      final File[] pControlFiles,
      final BigInteger pDataSize,
      final StringBuffer pChecksums,
      final File pOutput)
      throws IOException, ParseException {

    PackageDescriptor packageDescriptor = null;

    final TarOutputStream outputStream =
        new TarOutputStream(new GZIPOutputStream(new FileOutputStream(pOutput)));
    outputStream.setLongFileMode(TarOutputStream.LONGFILE_GNU);

    for (int i = 0; i < pControlFiles.length; i++) {
      final File file = pControlFiles[i];

      if (file.isDirectory()) {
        continue;
      }

      final TarEntry entry = new TarEntry(file);

      final String name = file.getName();

      entry.setName("./" + name);
      entry.setNames("root", "root");
      entry.setMode(PermMapper.toMode("755"));

      if ("control".equals(name)) {
        packageDescriptor = new PackageDescriptor(new FileInputStream(file), resolver);

        if (packageDescriptor.get("Date") == null) {
          SimpleDateFormat fmt =
              new SimpleDateFormat(
                  "EEE, d MMM yyyy HH:mm:ss Z",
                  Locale.ENGLISH); // Mon, 26 Mar 2007 11:44:04 +0200 (RFC 2822)
          // FIXME Is this field allowed in package descriptors ?
          packageDescriptor.set("Date", fmt.format(new Date()));
        }

        if (packageDescriptor.get("Distribution") == null) {
          packageDescriptor.set("Distribution", "unknown");
        }

        if (packageDescriptor.get("Urgency") == null) {
          packageDescriptor.set("Urgency", "low");
        }

        final String debFullName = System.getenv("DEBFULLNAME");
        final String debEmail = System.getenv("DEBEMAIL");

        if (debFullName != null && debEmail != null) {
          packageDescriptor.set("Maintainer", debFullName + " <" + debEmail + ">");
          console.println("Using maintainer from the environment variables.");
        }

        continue;
      }

      final InputStream inputStream = new FileInputStream(file);

      outputStream.putNextEntry(entry);

      Utils.copy(inputStream, outputStream);

      outputStream.closeEntry();

      inputStream.close();
    }

    if (packageDescriptor == null) {
      throw new FileNotFoundException("No control file in " + Arrays.toString(pControlFiles));
    }

    packageDescriptor.set("Installed-Size", pDataSize.divide(BigInteger.valueOf(1024)).toString());

    addEntry("control", packageDescriptor.toString(), outputStream);

    addEntry("md5sums", pChecksums.toString(), outputStream);

    outputStream.close();

    return packageDescriptor;
  }