Repository: GoogleContainerTools/jib
File: jib-core/src/main/java/com/google/cloud/tools/jib/tar/TarExtractor.java (Java)

Code before:
            try (OutputStream out = new BufferedOutputStream(Files.newOutputStream(entryPath))) {
              ByteStreams.copy(tarArchiveInputStream, out);
            }
          }
        }
      }
    }
    preserveModificationTimes(destination, entries, enableReproducibleTimestamps);
  }

  /**
   * Preserve modification time of files and directories in a tar file. If a directory is not an
   * entry in the tar file and reproducible timestamps are enabled then it's modification timestamp
   * is set to a constant value.
   *
   * @param destination target root for unzipping
   * @param entries list of entries in tar file
   * @param enableReproducibleTimestamps whether or not reproducible timestamps should be used
   * @throws IOException when I/O error occurs
   */
  private static void preserveModificationTimes(
      Path destination, List<TarArchiveEntry> entries, boolean enableReproducibleTimestamps)
      throws IOException {
    if (!Files.exists(destination)) {
      return;
    }
    if (enableReproducibleTimestamps) {
      FileTime epochPlusOne = FileTime.fromMillis(1000L);
      new DirectoryWalker(destination)
          .filter(path -> Files.isDirectory(path))
          .walk(path -> Files.setLastModifiedTime(path, epochPlusOne));
    }
    for (TarArchiveEntry entry : entries) {
      Files.setLastModifiedTime(
          destination.resolve(entry.getName()), FileTime.from(entry.getModTime().toInstant()));
    }
  }
}


Review comment (bug):
This can never be true. We already extracted files into `destination`.

And the check we talked about was only for when `enableReproducibleTimestamps` is true. That is, if it's enabled, we should proceed only when either 1) `destination` doesn't exist; or 2) `destination` exists but it's empty. (Or, I'm fine with the contract where `destination` must not exist when `enableReproducibleTimestamps` is true, if that's simpler.) In any case, this precondition should be documented in the Javadoc of `extract()`. That said, the check should be at the beginning of `extract()` so that it fails fast.

Code after:
        } else {
          if (entryPath.getParent() != null) {
            Files.createDirectories(entryPath.getParent());
          }

          if (entry.isSymbolicLink()) {
            Files.createSymbolicLink(entryPath, Paths.get(entry.getLinkName()));
          } else {
            try (OutputStream out = new BufferedOutputStream(Files.newOutputStream(entryPath))) {
              ByteStreams.copy(tarArchiveInputStream, out);
            }
          }
        }
      }
    }
    preserveModificationTimes(destination, entries, enableReproducibleTimestamps);
  }

  /**
   * Preserve modification timestamps of files and directories in a tar file. If a directory is not
   * an entry in the tar file and reproducible timestamps are enabled then its modification
   * timestamp is set to a constant value. Note that the modification timestamps of symbolic links
   * are not preserved even with reproducible timestamps enabled.
   *
   * @param destination target root for unzipping
   * @param entries list of entries in tar file
   * @param enableReproducibleTimestamps whether or not reproducible timestamps should be used
   * @throws IOException when I/O error occurs
   */
  private static void preserveModificationTimes(
      Path destination, List<TarArchiveEntry> entries, boolean enableReproducibleTimestamps)
      throws IOException {
    if (enableReproducibleTimestamps) {
      FileTime epochPlusOne = FileTime.fromMillis(1000L);
      new DirectoryWalker(destination)
          .filter(Files::isDirectory)
          .walk(path -> Files.setLastModifiedTime(path, epochPlusOne));
    }
    for (TarArchiveEntry entry : entries) {

      // Setting the symbolic link's modification timestamp will cause the modification timestamp of
      // the target to change
      if (!entry.isSymbolicLink()) {
        Files.setLastModifiedTime(
            destination.resolve(entry.getName()), FileTime.from(entry.getModTime().toInstant()));
      }
    }
  }
}