Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/jguild/jrpm/io/archive/CPIOPayloadArchive.java


1   package com.jguild.jrpm.io.archive;
2   
3   import com.jguild.jrpm.io.PayloadArchive;
4   import com.jguild.jrpm.io.RPMFile;
5   
6   import java.io.*;
7   import java.util.zip.GZIPInputStream;
8   import java.net.URLEncoder;
9   
10  import org.apache.log4j.Logger;
11  
12  
13  /**
14   * Allows to read/write CPIO archives.
15   */
16  public class CPIOPayloadArchive implements PayloadArchive {
17      private static final Logger logger = Logger.getLogger(CPIOPayloadArchive.class);
18      public static final int S_IFMT  = 0170000;
19      public static final int S_IFDIR = 0040000;
20      public static final int S_IFLNK = 0120000;
21      private byte compression;
22      private File file;
23      private int offset;
24  
25      /**
26       * Creates a new CPIOPayloadArchive object.
27       */
28      public CPIOPayloadArchive(byte compression, File file, int offset) {
29          this.compression = compression;
30          this.file = file;
31          this.offset = offset;
32      }
33  
34      /**
35       * Set compression type.
36       * @param compression Compression type.
37       */
38      public void setCompression(byte compression) {
39          this.compression = compression;
40      }
41  
42      /**
43       * Get compression type.
44       * @return Compression type.
45       */
46      public byte getCompression() {
47          return compression;
48      }
49  
50      /**
51       * Extract payload.
52       * @param basedir base directory to extract payload.
53       * @throws IOException If any I/O error happens.
54       * @todo support symbolic links
55       */
56      public synchronized void extract(File basedir) throws IOException {
57          DataInputStream in;
58          if( compression == PayloadArchive.COMPRESSION_GZIP ) {
59              in = new DataInputStream(new GZIPInputStream(new FileInputStream(file)));
60          } else {
61              in = new DataInputStream(new FileInputStream(file));
62          }
63          in.skip(offset);
64          int count = 0;
65          for(;;) {
66              byte[] magicBytes = new byte[6];
67              in.readFully(magicBytes);
68              count += magicBytes.length;
69              String magic = new String(magicBytes);
70              if( logger.isDebugEnabled() ) {
71                  logger.debug("CPIO Magic: "+magic);
72              }
73              if( ! magic.equals("070701")) {
74                  throw new IOException("Invalid magic: "+magic);
75              }
76              CPIOHeaderCRC hdr = new CPIOHeaderCRC( magicBytes, in );
77              count += hdr.hdrsize;
78              if( logger.isDebugEnabled() ) {
79                  logger.debug("CPIO Header: name="+hdr.name);
80                  logger.debug("CPIO Header: inode="+new String(hdr.inode));
81                  logger.debug("CPIO Header: mode="+Long.toOctalString(hdr.mode));
82                  logger.debug("CPIO Header: symlink ? = "+hdr.isSymlink() );
83                  logger.debug("CPIO Header: directory ? = "+hdr.isDir() );
84                  logger.debug("CPIO Header: nlink="+new String(hdr.nlink));
85                  logger.debug("CPIO Header: maj="+new String(hdr.maj));
86                  logger.debug("CPIO Header: min="+new String(hdr.min));
87                  logger.debug("CPIO Header: rmaj="+new String(hdr.rmaj));
88                  logger.debug("CPIO Header: rmin="+new String(hdr.rmin));
89              }
90              if( hdr.name.equals("TRAILER!!!") ) {
91                  in.close();
92                  return;
93              }
94              count += pad(in,count,4);
95              if( hdr.isDir() ) {
96                  new File(URLEncoder.encode(hdr.name,"UTF-8")).mkdirs();
97              } else {
98                  int idx = hdr.name.lastIndexOf('/');
99                  if( idx != -1 ) {
100                     new File( basedir + File.separator + hdr.name.substring(0,idx) ).mkdirs();
101                 }
102                 FileOutputStream out = new FileOutputStream( new File( basedir + File.separator + hdr.name ) );
103                 for( int i= 0 ; i < hdr.filesize ; i++ ) {
104                     int data = in.read();
105                     if( data == -1 ) {
106                         throw new EOFException("Unexpected end of payload.");
107                     }
108                     count ++;
109                     out.write(data);
110                 }
111                 out.close();
112             }
113             count += pad(in,count,4);
114         }
115     }
116 
117     private int pad( DataInputStream is, int count, int boundary ) throws IOException {
118         int r = count % boundary;
119         if( r > 0 ) {
120             int skip = boundary-r;
121             is.skipBytes(skip);
122             return skip;
123         }
124         return 0;
125     }
126 
127     public class CPIOHeaderCRC {
128         int hdrsize;
129         byte[] magic;
130         byte[] inode = new byte[8];
131         long mode;
132         byte[] uid = new byte[8];
133         byte[] gid = new byte[8];
134         byte[] nlink = new byte[8];
135         byte[] mtime = new byte[8];
136         long filesize;
137         byte[] maj = new byte[8];
138         byte[] min = new byte[8];
139         byte[] rmaj = new byte[8];
140         byte[] rmin = new byte[8];
141         long namesize;
142         byte[] chksum = new byte[8];
143         String name;
144 
145         /**
146          * Constructor for CPIOHeaderCRC
147          * @param magic
148          * @param in
149          * @throws IOException
150          * @throws EOFException
151          * @todo I've read that namesize needs to be round to nearest 2 byte boundary?
152          */
153         public CPIOHeaderCRC(byte[] magic, DataInputStream in ) throws IOException, EOFException {
154             this.magic = magic;
155             read(in,inode);
156             mode = readAsciiLong(in);
157             read(in,uid);
158             read(in,gid);
159             read(in,nlink);
160             read(in,mtime);
161             filesize = readAsciiLong(in);
162             read(in,maj);
163             read(in,min);
164             read(in,rmaj);
165             read(in,rmin);
166             namesize = readAsciiLong(in);
167             read(in,chksum);
168             byte[] _name = new byte[(int)namesize];
169             read(in,_name);
170             name = new String(_name,0,(int)namesize-1);
171         }
172 
173         private void read( DataInputStream in, byte[] data ) throws IOException {
174             in.readFully(data);
175             hdrsize += data.length;
176         }
177 
178         private long readAsciiLong( DataInputStream is ) throws IOException {
179             byte[] data = new byte[8];
180             is.readFully(data);
181             return Long.decode("0x"+new String(data)).longValue();
182         }
183 
184         boolean isSymlink() {
185             return (mode & S_IFMT) == S_IFLNK;
186         }
187 
188         boolean isDir() {
189             return (mode & S_IFMT) == S_IFDIR;
190         }
191     }
192 }