View Javadoc
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.zip;
20  
21  import static org.apache.commons.compress.AbstractTest.getFile;
22  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23  import static org.junit.jupiter.api.Assertions.assertEquals;
24  import static org.junit.jupiter.api.Assertions.assertNotEquals;
25  import static org.junit.jupiter.api.Assertions.assertSame;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.util.Enumeration;
29  import java.util.zip.ZipException;
30  
31  import org.apache.commons.compress.utils.ByteUtils;
32  import org.junit.jupiter.api.BeforeEach;
33  import org.junit.jupiter.api.Test;
34  
35  public class X7875_NewUnixTest {
36  
37      private static final ZipShort X7875 = new ZipShort(0x7875);
38  
39      private static byte[] trimTest(final byte[] b) {
40          return X7875_NewUnix.trimLeadingZeroesForceMinLength(b);
41      }
42  
43      private X7875_NewUnix xf;
44  
45      @BeforeEach
46      public void before() {
47          xf = new X7875_NewUnix();
48      }
49  
50      private void parseReparse(final long uid, final long gid, final byte[] expected, final long expectedUID, final long expectedGID) throws ZipException {
51  
52          // Initial local parse (init with garbage to avoid defaults causing test to pass).
53          xf.setUID(54321);
54          xf.setGID(12345);
55          xf.parseFromLocalFileData(expected, 0, expected.length);
56          assertEquals(expectedUID, xf.getUID());
57          assertEquals(expectedGID, xf.getGID());
58  
59          xf.setUID(uid);
60          xf.setGID(gid);
61          if (expected.length < 5) {
62              // We never emit zero-length entries.
63              assertEquals(5, xf.getLocalFileDataLength().getValue());
64          } else {
65              assertEquals(expected.length, xf.getLocalFileDataLength().getValue());
66          }
67          byte[] result = xf.getLocalFileDataData();
68          if (expected.length < 5) {
69              // We never emit zero-length entries.
70              assertArrayEquals(new byte[] { 1, 1, 0, 1, 0 }, result);
71          } else {
72              assertArrayEquals(expected, result);
73          }
74  
75          // And now we re-parse:
76          xf.parseFromLocalFileData(result, 0, result.length);
77  
78          // Did uid/gid change from re-parse? They shouldn't!
79          assertEquals(expectedUID, xf.getUID());
80          assertEquals(expectedGID, xf.getGID());
81  
82          assertEquals(0, xf.getCentralDirectoryLength().getValue());
83          result = xf.getCentralDirectoryData();
84          assertArrayEquals(ByteUtils.EMPTY_BYTE_ARRAY, result);
85  
86          // And now we re-parse:
87          xf.parseFromCentralDirectoryData(result, 0, result.length);
88  
89          // Did uid/gid change from 2nd re-parse? They shouldn't!
90          assertEquals(expectedUID, xf.getUID());
91          assertEquals(expectedGID, xf.getGID());
92      }
93  
94      @Test
95      public void testGetHeaderId() {
96          assertEquals(X7875, xf.getHeaderId());
97      }
98  
99      @Test
100     public void testMisc() throws Exception {
101         assertNotEquals(xf, new Object());
102         assertTrue(xf.toString().startsWith("0x7875 Zip Extra Field"));
103         final Object o = xf.clone();
104         assertEquals(o.hashCode(), xf.hashCode());
105         assertEquals(xf, o);
106         xf.setUID(12345);
107         assertNotEquals(xf, o);
108     }
109 
110     @Test
111     public void testParseReparse() throws ZipException {
112 
113         // Version=1, Len=0, Len=0.
114         final byte[] ZERO_LEN = { 1, 0, 0 };
115 
116         // Version=1, Len=1, zero, Len=1, zero.
117         final byte[] ZERO_UID_GID = { 1, 1, 0, 1, 0 };
118 
119         // Version=1, Len=1, one, Len=1, one
120         final byte[] ONE_UID_GID = { 1, 1, 1, 1, 1 };
121 
122         // Version=1, Len=2, one thousand, Len=2, one thousand
123         final byte[] ONE_THOUSAND_UID_GID = { 1, 2, -24, 3, 2, -24, 3 };
124 
125         // (2^32 - 2). I guess they avoid (2^32 - 1) since it's identical to -1 in
126         // two's complement, and -1 often has a special meaning.
127         final byte[] UNIX_MAX_UID_GID = { 1, 4, -2, -1, -1, -1, 4, -2, -1, -1, -1 };
128 
129         // Version=1, Len=5, 2^32, Len=5, 2^32 + 1
130         // Esoteric test: can we handle 40 bit numbers?
131         final byte[] LENGTH_5 = { 1, 5, 0, 0, 0, 0, 1, 5, 1, 0, 0, 0, 1 };
132 
133         // Version=1, Len=8, 2^63 - 2, Len=8, 2^63 - 1
134         // Esoteric test: can we handle 64-bit numbers?
135         final byte[] LENGTH_8 = { 1, 8, -2, -1, -1, -1, -1, -1, -1, 127, 8, -1, -1, -1, -1, -1, -1, -1, 127 };
136 
137         final long TWO_TO_32 = 0x100000000L;
138         final long MAX = TWO_TO_32 - 2;
139 
140         parseReparse(0, 0, ZERO_LEN, 0, 0);
141         parseReparse(0, 0, ZERO_UID_GID, 0, 0);
142         parseReparse(1, 1, ONE_UID_GID, 1, 1);
143         parseReparse(1000, 1000, ONE_THOUSAND_UID_GID, 1000, 1000);
144         parseReparse(MAX, MAX, UNIX_MAX_UID_GID, MAX, MAX);
145         parseReparse(-2, -2, UNIX_MAX_UID_GID, MAX, MAX);
146         parseReparse(TWO_TO_32, TWO_TO_32 + 1, LENGTH_5, TWO_TO_32, TWO_TO_32 + 1);
147         parseReparse(Long.MAX_VALUE - 1, Long.MAX_VALUE, LENGTH_8, Long.MAX_VALUE - 1, Long.MAX_VALUE);
148 
149         // We never emit this, but we should be able to parse it:
150         final byte[] SPURIOUS_ZEROES_1 = { 1, 4, -1, 0, 0, 0, 4, -128, 0, 0, 0 };
151         final byte[] EXPECTED_1 = { 1, 1, -1, 1, -128 };
152         xf.parseFromLocalFileData(SPURIOUS_ZEROES_1, 0, SPURIOUS_ZEROES_1.length);
153 
154         assertEquals(255, xf.getUID());
155         assertEquals(128, xf.getGID());
156         assertArrayEquals(EXPECTED_1, xf.getLocalFileDataData());
157 
158         final byte[] SPURIOUS_ZEROES_2 = { 1, 4, -1, -1, 0, 0, 4, 1, 2, 0, 0 };
159         final byte[] EXPECTED_2 = { 1, 2, -1, -1, 2, 1, 2 };
160         xf.parseFromLocalFileData(SPURIOUS_ZEROES_2, 0, SPURIOUS_ZEROES_2.length);
161 
162         assertEquals(65535, xf.getUID());
163         assertEquals(513, xf.getGID());
164         assertArrayEquals(EXPECTED_2, xf.getLocalFileDataData());
165     }
166 
167     @Test
168     public void testSampleFile() throws Exception {
169         try (ZipFile zf = ZipFile.builder().setFile(getFile("COMPRESS-211_uid_gid_zip_test.zip")).get()) {
170             final Enumeration<ZipArchiveEntry> en = zf.getEntries();
171 
172             // We expect EVERY entry of this ZIP file (dir & file) to
173             // contain extra field 0x7875.
174             while (en.hasMoreElements()) {
175 
176                 final ZipArchiveEntry zae = en.nextElement();
177                 final String name = zae.getName();
178                 final X7875_NewUnix xf = (X7875_NewUnix) zae.getExtraField(X7875);
179 
180                 // The directory entry in the test ZIP file is uid/gid 1000.
181                 long expected = 1000;
182                 if (name.contains("uid555_gid555")) {
183                     expected = 555;
184                 } else if (name.contains("uid5555_gid5555")) {
185                     expected = 5555;
186                 } else if (name.contains("uid55555_gid55555")) {
187                     expected = 55555;
188                 } else if (name.contains("uid555555_gid555555")) {
189                     expected = 555555;
190                 } else if (name.contains("min_unix")) {
191                     expected = 0;
192                 } else if (name.contains("max_unix")) {
193                     // 2^32-2 was the biggest UID/GID I could create on my Linux!
194                     // (December 2012, Linux kernel 3.4)
195                     expected = 0x100000000L - 2;
196                 }
197                 assertEquals(expected, xf.getUID());
198                 assertEquals(expected, xf.getGID());
199             }
200         }
201     }
202 
203     @Test
204     public void testTrimLeadingZeroesForceMinLength4() {
205         final byte[] NULL = null;
206         final byte[] EMPTY = ByteUtils.EMPTY_BYTE_ARRAY;
207         final byte[] ONE_ZERO = { 0 };
208         final byte[] TWO_ZEROES = { 0, 0 };
209         final byte[] FOUR_ZEROES = { 0, 0, 0, 0 };
210         final byte[] SEQUENCE = { 1, 2, 3 };
211         final byte[] SEQUENCE_LEADING_ZERO = { 0, 1, 2, 3 };
212         final byte[] SEQUENCE_LEADING_ZEROES = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
213         final byte[] TRAILING_ZERO = { 1, 2, 3, 0 };
214         final byte[] PADDING_ZERO = { 0, 1, 2, 3, 0 };
215         final byte[] SEQUENCE6 = { 1, 2, 3, 4, 5, 6 };
216         final byte[] SEQUENCE6_LEADING_ZERO = { 0, 1, 2, 3, 4, 5, 6 };
217 
218         assertSame(NULL, trimTest(NULL));
219         assertArrayEquals(ONE_ZERO, trimTest(EMPTY));
220         assertArrayEquals(ONE_ZERO, trimTest(ONE_ZERO));
221         assertArrayEquals(ONE_ZERO, trimTest(TWO_ZEROES));
222         assertArrayEquals(ONE_ZERO, trimTest(FOUR_ZEROES));
223         assertArrayEquals(SEQUENCE, trimTest(SEQUENCE));
224         assertArrayEquals(SEQUENCE, trimTest(SEQUENCE_LEADING_ZERO));
225         assertArrayEquals(SEQUENCE, trimTest(SEQUENCE_LEADING_ZEROES));
226         assertArrayEquals(TRAILING_ZERO, trimTest(TRAILING_ZERO));
227         assertArrayEquals(TRAILING_ZERO, trimTest(PADDING_ZERO));
228         assertArrayEquals(SEQUENCE6, trimTest(SEQUENCE6));
229         assertArrayEquals(SEQUENCE6, trimTest(SEQUENCE6_LEADING_ZERO));
230     }
231 }