ArArchiveEntry.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  * http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */
  19. package org.apache.commons.compress.archivers.ar;

  20. import java.io.File;
  21. import java.io.IOException;
  22. import java.nio.file.Files;
  23. import java.nio.file.LinkOption;
  24. import java.nio.file.Path;
  25. import java.util.Date;
  26. import java.util.Objects;

  27. import org.apache.commons.compress.archivers.ArchiveEntry;

  28. /**
  29.  * Represents an archive entry in the "ar" format.
  30.  * <p>
  31.  * Each AR archive starts with "!&lt;arch&gt;" followed by a LF. After these 8 bytes the archive entries are listed. The format of an entry header is as it
  32.  * follows:
  33.  * </p>
  34.  *
  35.  * <pre>
  36.  * START BYTE   END BYTE    NAME                    FORMAT      LENGTH
  37.  * 0            15          File name               ASCII       16
  38.  * 16           27          Modification timestamp  Decimal     12
  39.  * 28           33          Owner ID                Decimal     6
  40.  * 34           39          Group ID                Decimal     6
  41.  * 40           47          File mode               Octal       8
  42.  * 48           57          File size (bytes)       Decimal     10
  43.  * 58           59          File magic              \140\012    2
  44.  * </pre>
  45.  * <p>
  46.  * This specifies that an ar archive entry header contains 60 bytes.
  47.  * </p>
  48.  * <p>
  49.  * Due to the limitation of the file name length to 16 bytes GNU and BSD has their own variants of this format. Currently Commons Compress can read but not
  50.  * write the GNU variant. It fully supports the BSD variant.
  51.  * </p>
  52.  *
  53.  * @see <a href="https://www.freebsd.org/cgi/man.cgi?query=ar&sektion=5">ar man page</a>
  54.  * @Immutable
  55.  */
  56. public class ArArchiveEntry implements ArchiveEntry {

  57.     /** The header for each entry */
  58.     public static final String HEADER = "!<arch>\n";

  59.     /** The trailer for each entry {@code 0x60 0x0A} */
  60.     public static final String TRAILER = "`\012";

  61.     private static final int DEFAULT_MODE = 33188; // = (octal) 0100644

  62.     /**
  63.      * SVR4/GNU adds a trailing / to names; BSD does not. They also vary in how names longer than 16 characters are represented. (Not yet fully supported by
  64.      * this implementation)
  65.      */
  66.     private final String name;
  67.     private final int userId;
  68.     private final int groupId;
  69.     private final int mode;
  70.     private final long lastModified;
  71.     private final long length;

  72.     /**
  73.      * Creates a new instance using the attributes of the given file
  74.      *
  75.      * @param inputFile the file to create an entry from
  76.      * @param entryName the name of the entry
  77.      */
  78.     public ArArchiveEntry(final File inputFile, final String entryName) {
  79.         // TODO sort out mode
  80.         this(entryName, inputFile.isFile() ? inputFile.length() : 0, 0, 0, DEFAULT_MODE, inputFile.lastModified() / 1000);
  81.     }

  82.     /**
  83.      * Creates a new instance using the attributes of the given file
  84.      *
  85.      * @param inputPath the file to create an entry from
  86.      * @param entryName the name of the entry
  87.      * @param options   options indicating how symbolic links are handled.
  88.      * @throws IOException if an I/O error occurs.
  89.      * @since 1.21
  90.      */
  91.     public ArArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
  92.         this(entryName, Files.isRegularFile(inputPath, options) ? Files.size(inputPath) : 0, 0, 0, DEFAULT_MODE,
  93.                 Files.getLastModifiedTime(inputPath, options).toMillis() / 1000);
  94.     }

  95.     /**
  96.      * Constructs a new instance using a couple of default values.
  97.      *
  98.      * <p>
  99.      * Sets userId and groupId to 0, the octal file mode to 644 and the last modified time to the current time.
  100.      * </p>
  101.      *
  102.      * @param name   name of the entry
  103.      * @param length length of the entry in bytes
  104.      */
  105.     public ArArchiveEntry(final String name, final long length) {
  106.         this(name, length, 0, 0, DEFAULT_MODE, System.currentTimeMillis() / 1000);
  107.     }

  108.     /**
  109.      * Constructs a new instance.
  110.      *
  111.      * @param name         name of the entry
  112.      * @param length       length of the entry in bytes
  113.      * @param userId       numeric user id
  114.      * @param groupId      numeric group id
  115.      * @param mode         file mode
  116.      * @param lastModified last modified time in seconds since the epoch
  117.      */
  118.     public ArArchiveEntry(final String name, final long length, final int userId, final int groupId, final int mode, final long lastModified) {
  119.         this.name = name;
  120.         if (length < 0) {
  121.             throw new IllegalArgumentException("length must not be negative");
  122.         }
  123.         this.length = length;
  124.         this.userId = userId;
  125.         this.groupId = groupId;
  126.         this.mode = mode;
  127.         this.lastModified = lastModified;
  128.     }

  129.     @Override
  130.     public boolean equals(final Object obj) {
  131.         if (this == obj) {
  132.             return true;
  133.         }
  134.         if (obj == null || getClass() != obj.getClass()) {
  135.             return false;
  136.         }
  137.         final ArArchiveEntry other = (ArArchiveEntry) obj;
  138.         return Objects.equals(name, other.name);
  139.     }

  140.     /**
  141.      * Gets the group ID.
  142.      *
  143.      * @return the group ID.
  144.      */
  145.     public int getGroupId() {
  146.         return groupId;
  147.     }

  148.     /**
  149.      * Gets the last modified time in seconds since the epoch.
  150.      *
  151.      * @return the last modified date.
  152.      */
  153.     public long getLastModified() {
  154.         return lastModified;
  155.     }

  156.     @Override
  157.     public Date getLastModifiedDate() {
  158.         return new Date(1000 * getLastModified());
  159.     }

  160.     /**
  161.      * Gets the length.
  162.      *
  163.      * @return the length.
  164.      */
  165.     public long getLength() {
  166.         return length;
  167.     }

  168.     /**
  169.      * Gets the mode.
  170.      *
  171.      * @return the mode.
  172.      */
  173.     public int getMode() {
  174.         return mode;
  175.     }

  176.     @Override
  177.     public String getName() {
  178.         return name;
  179.     }

  180.     @Override
  181.     public long getSize() {
  182.         return getLength();
  183.     }

  184.     /**
  185.      * Gets the user ID.
  186.      *
  187.      * @return the user ID.
  188.      */
  189.     public int getUserId() {
  190.         return userId;
  191.     }

  192.     @Override
  193.     public int hashCode() {
  194.         return Objects.hash(name);
  195.     }

  196.     @Override
  197.     public boolean isDirectory() {
  198.         return false;
  199.     }
  200. }