KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > wizards > datatransfer > TarOutputStream


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.wizards.datatransfer;
12
13 import java.io.FilterOutputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.OutputStream JavaDoc;
16
17 /**
18  * Output stream for writing ustar archive files (tar) compatible
19  * with the specification in IEEE Std 1003.1-2001.
20  *
21  * @since 3.1
22  */

23 public class TarOutputStream extends FilterOutputStream JavaDoc {
24     
25     private int byteswritten = 0;
26     private int datapos = 0;
27     private long cursize = 0;
28
29     /**
30      * Creates a new tar output stream.
31      *
32      * @param out the stream to write to
33      */

34     public TarOutputStream(OutputStream JavaDoc out) {
35         super(out);
36     }
37
38     /**
39      * Close the output stream and write any necessary padding.
40      */

41     public void close() throws IOException JavaDoc {
42         // Spec says to write 1024 bytes of zeros at the end.
43
byte[] zeros = new byte[1024];
44         cursize = 1024;
45         write(zeros, 0, 1024);
46
47         // Default block size for tar files is 10240, so we have to
48
// pad the end of the file to be a multiple of this size.
49
if((byteswritten % 10240) != 0) {
50             int length = 10240 - (byteswritten % 10240);
51             cursize = length;
52             zeros = new byte[length];
53             write(zeros, 0, length);
54         }
55         super.close();
56     }
57
58     /**
59      * Close the current entry in the tar file. Must be called
60      * after each entry is completed.
61      *
62      * @throws IOException
63      */

64     public void closeEntry() throws IOException JavaDoc {
65         byte[] data = new byte[512];
66         int len = 512 - datapos;
67         if(len > 0 && datapos > 0) {
68             cursize = len;
69             write(data, 0, len);
70         }
71     }
72
73     /**
74      * The checksum of a tar file header is simply the sum of the bytes in
75      * the header.
76      *
77      * @param header
78      * @return checksum
79      */

80     private long headerChecksum(byte[] header) {
81         long sum = 0;
82         for(int i = 0; i < 512; i++) {
83             sum += header[i] & 0xff;
84         }
85         return sum;
86     }
87
88     /**
89      * Adds an entry for a new file in the tar archive.
90      *
91      * @param e TarEntry describing the file
92      * @throws IOException
93      */

94     public void putNextEntry(TarEntry e) throws IOException JavaDoc {
95         byte[] header = new byte[512];
96         String JavaDoc filename = e.getName();
97         String JavaDoc prefix = null;
98         int pos, i;
99         
100         /* Split filename into name and prefix if necessary. */
101         byte[] filenameBytes = filename.getBytes("UTF8"); //$NON-NLS-1$
102
if (filenameBytes.length > 99) {
103             int seppos = filename.lastIndexOf('/');
104             if(seppos == -1) {
105                 throw new IOException JavaDoc("filename too long"); //$NON-NLS-1$
106
}
107             prefix = filename.substring(0, seppos);
108             filename = filename.substring(seppos + 1);
109             filenameBytes = filename.getBytes("UTF8"); //$NON-NLS-1$
110
if (filenameBytes.length > 99) {
111                 throw new IOException JavaDoc("filename too long"); //$NON-NLS-1$
112
}
113         }
114         
115         /* Filename. */
116         pos = 0;
117         System.arraycopy(filenameBytes, 0, header, 0, filenameBytes.length);
118         pos += 100;
119         
120         /* File mode. */
121         StringBuffer JavaDoc mode = new StringBuffer JavaDoc(Long.toOctalString(e.getMode()));
122         while(mode.length() < 7) {
123             mode.insert(0,'0');
124         }
125         for(i = 0; i < 7; i++) {
126             header[pos + i] = (byte) mode.charAt(i);
127         }
128         pos += 8;
129         
130         /* UID. */
131         header[pos] = '0';
132         pos += 8;
133         
134         /* GID. */
135         header[pos] = '0';
136         pos += 8;
137         
138         /* Length of the file. */
139         String JavaDoc length = Long.toOctalString(e.getSize());
140         for(i = 0; i < length.length(); i++) {
141             header[pos + i] = (byte) length.charAt(i);
142         }
143         pos += 12;
144         
145         /* mtime */
146         String JavaDoc mtime = Long.toOctalString(e.getTime());
147         for(i = 0; i < mtime.length(); i++) {
148             header[pos + i] = (byte) mtime.charAt(i);
149         }
150         pos += 12;
151         
152         /* "Blank" out the checksum. */
153         for(i = 0; i < 8; i++) {
154             header[pos + i] = ' ';
155         }
156         pos += 8;
157         
158         /* Link flag. */
159         header[pos] = (byte) e.getFileType();
160         pos += 1;
161
162         /* Link destination. */
163         pos += 100;
164
165         /* Add ustar header. */
166         String JavaDoc ustar = "ustar 00"; //$NON-NLS-1$
167
for(i = 0; i < ustar.length(); i++) {
168             header[pos + i] = (byte) ustar.charAt(i);
169         }
170         header[pos + 5] = 0;
171         pos += 8;
172         
173         /* Username. */
174         String JavaDoc uname = "nobody"; //$NON-NLS-1$
175
for(i = 0; i < uname.length(); i++) {
176             header[pos + i] = (byte) uname.charAt(i);
177         }
178         pos += 32;
179         
180         
181         /* Group name. */
182         String JavaDoc gname = "nobody"; //$NON-NLS-1$
183
for(i = 0; i < gname.length(); i++) {
184             header[pos + i] = (byte) gname.charAt(i);
185         }
186         pos += 32;
187         
188         /* Device major. */
189         pos += 8;
190
191         /* Device minor. */
192         pos += 8;
193
194         /* File prefix. */
195         if(prefix != null) {
196             byte[] prefixBytes = prefix.getBytes("UTF8"); //$NON-NLS-1$
197
if (prefixBytes.length > 155) {
198                 throw new IOException JavaDoc("prefix too large"); //$NON-NLS-1$
199
}
200             System.arraycopy(prefixBytes, 0, header, pos, prefixBytes.length);
201         }
202
203         long sum = headerChecksum(header);
204         pos = 100 + 8 + 8 + 8 + 12 + 12;
205         String JavaDoc sumval = Long.toOctalString(sum);
206         for(i = 0; i < sumval.length(); i++) {
207             header[pos + i] = (byte) sumval.charAt(i);
208         }
209
210         cursize = 512;
211         write(header, 0, 512);
212         
213         cursize = e.getSize();
214     }
215
216     /**
217      * Writes data for the current file into the archive.
218      */

219     public void write(byte[] b, int off, int len) throws IOException JavaDoc {
220         super.write(b, off, len);
221         datapos = (datapos + len) % 512;
222         byteswritten += len;
223         cursize -= len;
224         if(cursize < 0) {
225             throw new IOException JavaDoc("too much data written for current file"); //$NON-NLS-1$
226
}
227     }
228 }
229
Popular Tags