Uploaded image for project: 'Commons Compress'
  1. Commons Compress
  2. COMPRESS-613

Write ZIP extra time fields automatically

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • 1.21
    • 1.23.0
    • Archivers

    Description

      When writing to a Zip file through ZipArchiveOutputStream, setting creation and access times in a ZipArchiveEntry does not cause these to be reflected as X5455 or X000A extra fields in the resulting zip file. This also happens for modification times that do not fit into an MS-DOS time.

      As a consequence, the date range is reduced, as well as the granularity (form 100ns intervals to seconds).

      ZipEntry and standard java.util.zip facilities do that automatically, but that's missing here.

      My proposal is to use the same logic the java.util.zip do and add those extra fields automatically, if situation requires them.

      See my existing logic for this here: https://github.com/andrebrait/DATROMTool/blob/86a4f4978bab250ca54d047c58b4f91e7dbbcc7f/core/src/main/java/io/github/datromtool/io/FileCopier.java#L1425

      It's (almost) the same logic from java.util.zip, but adapted to be used with ZipArchiveEntry.

      If you're ok with it, I can send a PR.

      Actual logic will be more like java.util.zip.ZipOutputStream#writeLOC(XEntry), represented below:

              int elenEXTT = 0;         // info-zip extended timestamp
              int flagEXTT = 0;
              long umtime = -1;
              long uatime = -1;
              long uctime = -1;
              if (e.mtime != null) {
                  elenEXTT += 4;
                  flagEXTT |= EXTT_FLAG_LMT;
                  umtime = fileTimeToUnixTime(e.mtime);
              }
              if (e.atime != null) {
                  elenEXTT += 4;
                  flagEXTT |= EXTT_FLAG_LAT;
                  uatime = fileTimeToUnixTime(e.atime);
              }
              if (e.ctime != null) {
                  elenEXTT += 4;
                  flagEXTT |= EXTT_FLAT_CT;
                  uctime = fileTimeToUnixTime(e.ctime);
              }
              if (flagEXTT != 0) {
                  // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
                  if (umtime > UPPER_UNIXTIME_BOUND ||
                      uatime > UPPER_UNIXTIME_BOUND ||
                      uctime > UPPER_UNIXTIME_BOUND) {
                      elen += 36;                // NTFS time, total 36 bytes
                  } else {
                      elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
                  }
              }
              writeShort(elen);
              writeBytes(nameBytes, 0, nameBytes.length);
              if (hasZip64) {
                  writeShort(ZIP64_EXTID);
                  writeShort(16);
                  writeLong(e.size);
                  writeLong(e.csize);
              }
              if (flagEXTT != 0) {
                  if (umtime > UPPER_UNIXTIME_BOUND ||
                      uatime > UPPER_UNIXTIME_BOUND ||
                      uctime > UPPER_UNIXTIME_BOUND) {
                      writeShort(EXTID_NTFS);    // id
                      writeShort(32);            // data size
                      writeInt(0);               // reserved
                      writeShort(0x0001);        // NTFS attr tag
                      writeShort(24);
                      writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
                                                : fileTimeToWinTime(e.mtime));
                      writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
                                                : fileTimeToWinTime(e.atime));
                      writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
                                                : fileTimeToWinTime(e.ctime));
                  } else {
                      writeShort(EXTID_EXTT);
                      writeShort(elenEXTT + 1);  // flag + data
                      writeByte(flagEXTT);
                      if (e.mtime != null)
                          writeInt(umtime);
                      if (e.atime != null)
                          writeInt(uatime);
                      if (e.ctime != null)
                          writeInt(uctime);
                  }
              }
              writeExtra(e.extra);
              locoff = written;
      

      Attachments

        Activity

          People

            Unassigned Unassigned
            andrebrait Andre Brait
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0h
                0h
                Logged:
                Time Spent - 3h 20m
                3h 20m