Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 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.tar; |
| 20 | |
| 21 | import java.io.FilterOutputStream; |
| 22 | import java.io.IOException; |
| 23 | import java.io.InputStream; |
| 24 | import java.io.OutputStream; |
| 25 | |
| 26 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 27 | * The TarOutputStream writes a UNIX tar archive as an OutputStream. |
| 28 | * Methods are provided to put entries, and then write their contents |
| 29 | * by writing to this stream using write(). |
| 30 | * |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 31 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 32 | public class TarOutputStream extends FilterOutputStream { |
| 33 | /** Fail if a long file name is required in the archive. */ |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 34 | public static final int LONGFILE_ERROR = 0; |
| 35 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 36 | /** Long paths will be truncated in the archive. */ |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 37 | public static final int LONGFILE_TRUNCATE = 1; |
| 38 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 39 | /** GNU tar extensions are used to store long file names in the archive. */ |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 40 | public static final int LONGFILE_GNU = 2; |
| 41 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 42 | // CheckStyle:VisibilityModifier OFF - bc |
| 43 | protected boolean debug; |
| 44 | protected long currSize; |
| 45 | protected String currName; |
| 46 | protected long currBytes; |
| 47 | protected byte[] oneBuf; |
| 48 | protected byte[] recordBuf; |
| 49 | protected int assemLen; |
| 50 | protected byte[] assemBuf; |
| 51 | protected TarBuffer buffer; |
| 52 | protected int longFileMode = LONGFILE_ERROR; |
| 53 | // CheckStyle:VisibilityModifier ON |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 54 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 55 | private boolean closed = false; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 56 | |
| 57 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 58 | * Constructor for TarInputStream. |
| 59 | * @param os the output stream to use |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 60 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 61 | public TarOutputStream(OutputStream os) { |
| 62 | this(os, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 66 | * Constructor for TarInputStream. |
| 67 | * @param os the output stream to use |
| 68 | * @param blockSize the block size to use |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 69 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 70 | public TarOutputStream(OutputStream os, int blockSize) { |
| 71 | this(os, blockSize, TarBuffer.DEFAULT_RCDSIZE); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 75 | * Constructor for TarInputStream. |
| 76 | * @param os the output stream to use |
| 77 | * @param blockSize the block size to use |
| 78 | * @param recordSize the record size to use |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 79 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 80 | public TarOutputStream(OutputStream os, int blockSize, int recordSize) { |
| 81 | super(os); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 82 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 83 | this.buffer = new TarBuffer(os, blockSize, recordSize); |
| 84 | this.debug = false; |
| 85 | this.assemLen = 0; |
| 86 | this.assemBuf = new byte[recordSize]; |
| 87 | this.recordBuf = new byte[recordSize]; |
| 88 | this.oneBuf = new byte[1]; |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Set the long file mode. |
| 93 | * This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or LONGFILE_GNU(2). |
| 94 | * This specifies the treatment of long file names (names >= TarConstants.NAMELEN). |
| 95 | * Default is LONGFILE_ERROR. |
| 96 | * @param longFileMode the mode to use |
| 97 | */ |
| 98 | public void setLongFileMode(int longFileMode) { |
| 99 | this.longFileMode = longFileMode; |
| 100 | } |
| 101 | |
| 102 | |
| 103 | /** |
| 104 | * Sets the debugging flag. |
| 105 | * |
| 106 | * @param debugF True to turn on debugging. |
| 107 | */ |
| 108 | public void setDebug(boolean debugF) { |
| 109 | this.debug = debugF; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Sets the debugging flag in this stream's TarBuffer. |
| 114 | * |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 115 | * @param debug True to turn on debugging. |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 116 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 117 | public void setBufferDebug(boolean debug) { |
| 118 | buffer.setDebug(debug); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 122 | * Ends the TAR archive without closing the underlying OutputStream. |
| 123 | * The result is that the two EOF records of nulls are written. |
| 124 | * @throws IOException on error |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 125 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 126 | public void finish() throws IOException { |
| 127 | // See Bugzilla 28776 for a discussion on this |
| 128 | // http://issues.apache.org/bugzilla/show_bug.cgi?id=28776 |
| 129 | writeEOFRecord(); |
| 130 | writeEOFRecord(); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Ends the TAR archive and closes the underlying OutputStream. |
| 135 | * This means that finish() is called followed by calling the |
| 136 | * TarBuffer's close(). |
| 137 | * @throws IOException on error |
| 138 | */ |
| 139 | public void close() throws IOException { |
| 140 | if (!closed) { |
| 141 | finish(); |
| 142 | buffer.close(); |
| 143 | out.close(); |
| 144 | closed = true; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 145 | } |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | /** |
| 149 | * Get the record size being used by this stream's TarBuffer. |
| 150 | * |
| 151 | * @return The TarBuffer record size. |
| 152 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 153 | public int getRecordSize() { |
| 154 | return buffer.getRecordSize(); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 158 | * Put an entry on the output stream. This writes the entry's |
| 159 | * header record and positions the output stream for writing |
| 160 | * the contents of the entry. Once this method is called, the |
| 161 | * stream is ready for calls to write() to write the entry's |
| 162 | * contents. Once the contents are written, closeEntry() |
| 163 | * <B>MUST</B> be called to ensure that all buffered data |
| 164 | * is completely written to the output stream. |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 165 | * |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 166 | * @param entry The TarEntry to be written to the archive. |
| 167 | * @throws IOException on error |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 168 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 169 | public void putNextEntry(TarArchiveEntry entry) throws IOException { |
| 170 | if (entry.getName().length() >= TarConstants.NAMELEN) { |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 171 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 172 | if (longFileMode == LONGFILE_GNU) { |
| 173 | // create a TarEntry for the LongLink, the contents |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 174 | // of which are the entry's name |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 175 | TarArchiveEntry longLinkEntry = new TarArchiveEntry(TarConstants.GNU_LONGLINK, |
| 176 | TarConstants.LF_GNUTYPE_LONGNAME); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 177 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 178 | longLinkEntry.setSize(entry.getName().length() + 1); |
| 179 | putNextEntry(longLinkEntry); |
| 180 | write(entry.getName().getBytes()); |
| 181 | write(0); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 182 | closeEntry(); |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 183 | } else if (longFileMode != LONGFILE_TRUNCATE) { |
| 184 | throw new RuntimeException("file name '" + entry.getName() |
| 185 | + "' is too long ( > " |
| 186 | + TarConstants.NAMELEN + " bytes)"); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 187 | } |
| 188 | } |
| 189 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 190 | entry.writeEntryHeader(recordBuf); |
| 191 | buffer.writeRecord(recordBuf); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 192 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 193 | currBytes = 0; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 194 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 195 | if (entry.isDirectory()) { |
| 196 | currSize = 0; |
| 197 | } else { |
| 198 | currSize = entry.getSize(); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 199 | } |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 200 | currName = entry.getName(); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 204 | * Close an entry. This method MUST be called for all file |
| 205 | * entries that contain data. The reason is that we must |
| 206 | * buffer data written to the stream in order to satisfy |
| 207 | * the buffer's record based writes. Thus, there may be |
| 208 | * data fragments still being assembled that must be written |
| 209 | * to the output stream before this entry is closed and the |
| 210 | * next entry written. |
| 211 | * @throws IOException on error |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 212 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 213 | public void closeEntry() throws IOException { |
| 214 | if (assemLen > 0) { |
| 215 | for (int i = assemLen; i < assemBuf.length; ++i) { |
| 216 | assemBuf[i] = 0; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 217 | } |
| 218 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 219 | buffer.writeRecord(assemBuf); |
| 220 | |
| 221 | currBytes += assemLen; |
| 222 | assemLen = 0; |
| 223 | } |
| 224 | |
| 225 | if (currBytes < currSize) { |
| 226 | throw new IOException("entry '" + currName + "' closed at '" |
| 227 | + currBytes |
| 228 | + "' before the '" + currSize |
| 229 | + "' bytes specified in the header were written"); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 230 | } |
| 231 | } |
| 232 | |
| 233 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 234 | * Writes a byte to the current tar archive entry. |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 235 | * |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 236 | * This method simply calls read( byte[], int, int ). |
| 237 | * |
| 238 | * @param b The byte written. |
| 239 | * @throws IOException on error |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 240 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 241 | public void write(int b) throws IOException { |
| 242 | oneBuf[0] = (byte) b; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 243 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 244 | write(oneBuf, 0, 1); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 248 | * Writes bytes to the current tar archive entry. |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 249 | * |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 250 | * This method simply calls write( byte[], int, int ). |
| 251 | * |
| 252 | * @param wBuf The buffer to write to the archive. |
| 253 | * @throws IOException on error |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 254 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 255 | public void write(byte[] wBuf) throws IOException { |
| 256 | write(wBuf, 0, wBuf.length); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 257 | } |
| 258 | |
| 259 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 260 | * Writes bytes to the current tar archive entry. This method |
| 261 | * is aware of the current entry and will throw an exception if |
| 262 | * you attempt to write bytes past the length specified for the |
| 263 | * current entry. The method is also (painfully) aware of the |
| 264 | * record buffering required by TarBuffer, and manages buffers |
| 265 | * that are not a multiple of recordsize in length, including |
| 266 | * assembling records from small buffers. |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 267 | * |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 268 | * @param wBuf The buffer to write to the archive. |
| 269 | * @param wOffset The offset in the buffer from which to get bytes. |
| 270 | * @param numToWrite The number of bytes to write. |
| 271 | * @throws IOException on error |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 272 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 273 | public void write(byte[] wBuf, int wOffset, int numToWrite) throws IOException { |
| 274 | if ((currBytes + numToWrite) > currSize) { |
| 275 | throw new IOException("request to write '" + numToWrite |
| 276 | + "' bytes exceeds size in header of '" |
| 277 | + currSize + "' bytes for entry '" |
| 278 | + currName + "'"); |
| 279 | |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 280 | // |
| 281 | // We have to deal with assembly!!! |
| 282 | // The programmer can be writing little 32 byte chunks for all |
| 283 | // we know, and we must assemble complete records for writing. |
| 284 | // REVIEW Maybe this should be in TarBuffer? Could that help to |
| 285 | // eliminate some of the buffer copying. |
| 286 | // |
| 287 | } |
| 288 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 289 | if (assemLen > 0) { |
| 290 | if ((assemLen + numToWrite) >= recordBuf.length) { |
| 291 | int aLen = recordBuf.length - assemLen; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 292 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 293 | System.arraycopy(assemBuf, 0, recordBuf, 0, |
| 294 | assemLen); |
| 295 | System.arraycopy(wBuf, wOffset, recordBuf, |
| 296 | assemLen, aLen); |
| 297 | buffer.writeRecord(recordBuf); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 298 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 299 | currBytes += recordBuf.length; |
| 300 | wOffset += aLen; |
| 301 | numToWrite -= aLen; |
| 302 | assemLen = 0; |
| 303 | } else { |
| 304 | System.arraycopy(wBuf, wOffset, assemBuf, assemLen, |
| 305 | numToWrite); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 306 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 307 | wOffset += numToWrite; |
| 308 | assemLen += numToWrite; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 309 | numToWrite -= numToWrite; |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | // |
| 314 | // When we get here we have EITHER: |
| 315 | // o An empty "assemble" buffer. |
| 316 | // o No bytes to write (numToWrite == 0) |
| 317 | // |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 318 | while (numToWrite > 0) { |
| 319 | if (numToWrite < recordBuf.length) { |
| 320 | System.arraycopy(wBuf, wOffset, assemBuf, assemLen, |
| 321 | numToWrite); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 322 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 323 | assemLen += numToWrite; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 324 | |
| 325 | break; |
| 326 | } |
| 327 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 328 | buffer.writeRecord(wBuf, wOffset); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 329 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 330 | int num = recordBuf.length; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 331 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 332 | currBytes += num; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 333 | numToWrite -= num; |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 334 | wOffset += num; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 335 | } |
| 336 | } |
| 337 | |
| 338 | /** |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 339 | * Write an EOF (end of archive) record to the tar archive. |
| 340 | * An EOF record consists of a record of all zeros. |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 341 | */ |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 342 | private void writeEOFRecord() throws IOException { |
| 343 | for (int i = 0; i < recordBuf.length; ++i) { |
| 344 | recordBuf[i] = 0; |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 345 | } |
| 346 | |
Torsten Curdt | 46ad24d | 2009-01-08 11:09:25 +0000 | [diff] [blame^] | 347 | buffer.writeRecord(recordBuf); |
Torsten Curdt | ca16539 | 2008-07-10 10:17:44 +0000 | [diff] [blame] | 348 | } |
| 349 | } |