View Javadoc

1   /*
2    * jGuild Project: jRPM
3    * Released under the Apache License ( http://www.apache.org/LICENSE )
4    */
5   package com.jguild.jrpm.io.cpio;
6   
7   /***
8    * A cpio archive consists of a sequence of files.
9    * There are several types of headers defided in two
10   * categories of new and old format.
11   * The headers are recognized by magic numbers:
12   * "070701" ascii for "new" portable format
13   * "070702" ascii for "new" portable format with CRC format
14   * "070707" ascii for old ascii
15   * "070707" short for old binary
16   * CPIO 2.5 knows also about tar, but it is not recognized here.
17   *
18   * OLD FORMAT:
19   * Each file has a 76(ascii)/26(binary) byte header,
20   * a variable length, NUL terminated filename,
21   * and variable length file data.
22   * A header for a filename "TRAILER!!!" indicates the end of the archive.
23   * 
24   * All the fields in the header are ISO 646 (approximately ASCII) strings
25   * of octal numbers, left padded, not NUL terminated.
26   *
27   * Field Name   Length in Bytes    Notes
28   *              ASCII / BINARY
29   *  c_magic     6     / 2           
30   *  c_dev       6     / 2          Device that contains a directory entry for this file
31   *  c_ino       6     / 2          I-node number that identifies the input file to the file system
32   *  c_mode      6     / 2          Mode of the input file
33   *  c_uid       6     / 2          User ID of the owner of the input file
34   *  c_gid       6     / 2          Group ID of the owner of the input file
35   *  c_nlink     6     / 2          Number of links that are connected to the input file
36   *  c_rdev      6     / 2          ID of the remote device from which the input file is taken
37   *                                 only valid for chr and blk special files
38   *  c_mtime     11    / 4          Time when data was last modified. For remote files,
39   *                                 this field contains the time at the server
40   *  c_namesize  6     / 2          Length of the path name, including the terminating null byte
41   *  c_filesize  11    / 4          Length of the file in bytes. This is the length of the data
42   *                                 section that follows the header structure. Must be 0 for
43   *                                 FIFOs and directories
44   *
45   * Special files, directories, and the trailer are recorded with the h_filesize field equal to 0.
46   *
47   * NEW FORMAT:
48   * Each file has a 110 byte header,
49   * a variable length, NUL terminated filename,
50   * and variable length file data.
51   * A header for a filename "TRAILER!!!" indicates the end of the archive.
52   * All the fields in the header are ISO 646 (approximately ASCII) strings
53   * of hexadecimal numbers, left padded, not NUL terminated.
54   *
55   * Field Name   Length in Bytes    Notes
56   *  c_magic     6        
57   *  c_ino       8        
58   *  c_mode      8        
59   *  c_uid       8        
60   *  c_gid       8        
61   *  c_nlink     8        
62   *  c_mtime     8        
63   *  c_filesize  8                  must be 0 for FIFOs and directories
64   *  c_maj       8        
65   *  c_min       8        
66   *  c_rmaj      8                  only valid for chr and blk special files
67   *  c_rmin      8                  only valid for chr and blk special files
68   *  c_namesize  8                  count includes terminating NUL in pathname
69   *  c_chksum    8                  0 for "new" portable format; for CRC format
70   *                                 the sum of all the bytes in the file
71   *
72   * @author Michael Kuss
73   */
74  public class CPIOEntry implements CPIOConstants {
75      private long chksum = 0;
76      private short fileFormat = -1;
77      private long filesize = 0;
78      private long gid = 0;
79      private long headerSize = -1;
80      private long inode = 0;
81      private long maj = 0;
82      private long min = 0;
83      private long mode = -1;
84      private long mtime = -1;
85      private String name;
86      private long nlink = 0;
87      private long rmaj = 0;
88      private long rmin = 0;
89      private long uid = 0;
90  
91      /***
92       * Ceates a CPIOEntry without a cpio format.
93       */
94      public CPIOEntry() {
95      }
96  
97      /***
98       * Ceates a CPIOEntry with a specified format.
99       * 
100      * @param format The cpio format for this entry.
101      */
102     public CPIOEntry(short format) {
103         setFormat(format);
104     }
105 
106     /***
107      * Ceates a CPIOEntry with a specified name.
108      * The format of this entry will be the new format.
109      * 
110      * @param name The name of this entry.
111      */
112     public CPIOEntry(String name) {
113         this(FORMAT_NEW);
114         this.name = name;
115     }
116 
117     /***
118      * Check if the method is allowed for the defined format.
119      */
120     private void checkNewFormat() {
121         if ((fileFormat & FORMAT_NEW_MASK) == 0)
122                 throw new UnsupportedOperationException();
123     }
124 
125     /***
126      * Check if the method is allowed for the defined format.
127      */
128     private void checkOldFormat() {
129         if ((fileFormat & FORMAT_OLD_MASK) == 0)
130                 throw new UnsupportedOperationException();
131     }
132 
133     /***
134      * Get the checksum.
135      * 
136      * @return Returns the checksum.
137      */
138     public long getChksum() {
139         checkNewFormat();
140         return chksum;
141     }
142 
143     /***
144      * Get the device id.
145      * 
146      * @return Returns the device id.
147      * @throws UnsupportedOperationException if this method is called
148      *            for a CPIOEntry with a new format.
149      */
150     public long getDevice() {
151         checkOldFormat();
152         return min;
153     }
154 
155     /***
156      * Get the major device id.
157      * 
158      * @return Returns the major device id.
159      * @throws UnsupportedOperationException if this method is called
160      *            for a CPIOEntry with an old format.
161      */
162     public long getDeviceMaj() {
163         checkNewFormat();
164         return maj;
165     }
166 
167     /***
168      * Get the minor device id
169      * 
170      * @return Returns the minor device id.
171      */
172     public long getDeviceMin() {
173         checkNewFormat();
174         return min;
175     }
176 
177     /***
178      * Get the filesize.
179      * 
180      * @return Returns the filesize.
181      */
182     public long getFileSize() {
183         return filesize;
184     }
185 
186     /***
187      * Get the format for this entry.
188      * 
189      * @return Returns the format.
190      */
191     public short getFormat() {
192         return fileFormat;
193     }
194 
195     /***
196      * Get the group id.
197      * 
198      * @return Returns the group id.
199      */
200     public long getGID() {
201         return gid;
202     }
203 
204     /***
205      * Get the size of this entry on the stream
206      * 
207      * @return Returns the size.
208      */
209     public long getHeaderSize() {
210         return headerSize;
211     }
212 
213     /***
214      * Set the inode.
215      * 
216      * @return Returns the inode.
217      */
218     public long getInode() {
219         return inode;
220     }
221 
222     /***
223      * Get the mode of this entry (e.g. directory, regular file).
224      * 
225      * @return Returns the mode.
226      */
227     public long getMode() {
228         return mode;
229     }
230 
231     /***
232      * Get the name.
233      * 
234      * @return Returns the name.
235      */
236     public String getName() {
237         return name;
238     }
239 
240     /***
241      * Get the number of links.
242      * 
243      * @return Returns the number of links.
244      */
245     public long getNumberOfLinks() {
246         return nlink;
247     }
248 
249     /***
250      * Get the remote device id.
251      * 
252      * @return Returns the remote device id.
253      * @throws UnsupportedOperationException if this method is called
254      *            for a CPIOEntry with a new format.
255      */
256     public long getRemoteDevice() {
257         checkOldFormat();
258         return rmin;
259     }
260 
261     /***
262      * Get the remote major device id.
263      * 
264      * @return Returns the remote major device id.
265      * @throws UnsupportedOperationException if this method is called
266      *            for a CPIOEntry with an old format.
267      */
268     public long getRemoteDeviceMaj() {
269         checkNewFormat();
270         return rmaj;
271     }
272 
273     /***
274      * Get the remote minor device id.
275      * 
276      * @return Returns the remote minor device id.
277      * @throws UnsupportedOperationException if this method is called
278      *            for a CPIOEntry with an old format.
279      */
280     public long getRemoteDeviceMin() {
281         checkNewFormat();
282         return rmin;
283     }
284 
285     /***
286      * Get the time in seconds.
287      * 
288      * @return Returns the time.
289      */
290     public long getTime() {
291         return mtime;
292     }
293 
294     /***
295      * Get the user id.
296      * 
297      * @return Returns the user id.
298      */
299     public long getUID() {
300         return uid;
301     }
302 
303     /***
304      * Check if this entry represents a block device. 
305      * 
306      * @return TRUE if this entry is a block device.
307      */
308     public boolean isBlockDevice() {
309         return (mode & S_IFMT) == C_ISBLK;
310     }
311 
312     /***
313      * Check if this entry represents a character device.
314      * 
315      * @return TRUE if this entry is a character device. 
316      */
317     public boolean isCharacterDevice() {
318         return (mode & S_IFMT) == C_ISCHR;
319     }
320 
321     /***
322      * Check if this entry represents a directory.
323      * 
324      * @return TRUE if this entry is a directory.
325      */
326     public boolean isDirectory() {
327         return (mode & S_IFMT) == C_ISDIR;
328     }
329 
330     /***
331      * Check if this entry represents a network device. 
332      * 
333      * @return TRUE if this entry is a network device.
334      */
335     public boolean isNetwork() {
336         return (mode & S_IFMT) == C_ISNWK;
337     }
338 
339     /***
340      * Check if this entry represents a pipe. 
341      * 
342      * @return TRUE if this entry is a pipe. 
343      */
344     public boolean isPipe() {
345         return (mode & S_IFMT) == C_ISFIFO;
346     }
347 
348     /***
349      * Check if this entry represents a regular file. 
350      * 
351      * @return TRUE if this entry is a regular file. 
352      */
353     public boolean isRegularFile() {
354         return (mode & S_IFMT) == C_ISREG;
355     }
356 
357     /***
358      * Check if this entry represents a socket.
359      * 
360      * @return TRUE if this entry is a socket. 
361      */
362     public boolean isSocket() {
363         return (mode & S_IFMT) == C_ISSOCK;
364     }
365 
366     /***
367      * Check if this entry represents a symbolic link.
368      * 
369      * @return TRUE if this entry is a symbolic link.
370      */
371     public boolean isSymbolicLink() {
372         return (mode & S_IFMT) == C_ISLNK;
373     }
374 
375     /***
376      * Set the checksum.
377      * The checksum is calculated by adding all bytes of a
378      * file to transfer (crc += buf[pos] & 0xFF).
379      * 
380      * @param chksum The checksum to set.
381      */
382     public void setChksum(long chksum) {
383         checkNewFormat();
384         this.chksum = chksum;
385     }
386 
387     /***
388      * Set the device id.
389      * 
390      * @param device The device id to set.
391      * @throws UnsupportedOperationException if this method is called
392      *            for a CPIOEntry with a new format.
393      */
394     public void setDevice(long device) {
395         checkOldFormat();
396         this.min = device;
397     }
398 
399     /***
400      * Set major device id.
401      * 
402      * @param maj The major device id to set.
403      */
404     public void setDeviceMaj(long maj) {
405         checkNewFormat();
406         this.maj = maj;
407     }
408 
409     /***
410      * Set the minor device id
411      * 
412      * @param min The minor device id to set.
413      */
414     public void setDeviceMin(long min) {
415         checkNewFormat();
416         this.min = min;
417     }
418 
419     /***
420      * Set the filesize.
421      * 
422      * @param size The filesize to set.
423      */
424     public void setFileSize(long size) {
425         if (size < 0 || size > 0xFFFFFFFFL) { throw new IllegalArgumentException(
426                 "invalid entry size <" + size + ">"); }
427         filesize = size;
428     }
429 
430     /***
431      * Set the format for this entry.
432      * Possible values are:
433      * CPIOConstants.FORMAT_NEW, CPIOConstants.FORMAT_NEW_CRC,
434      * CPIOConstants.FORMAT_OLD_BINARY, CPIOConstants.FORMAT_OLD_ASCII
435      * 
436      * @param format The format to set.
437      */
438     void setFormat(short format) {
439         switch (format) {
440         case FORMAT_NEW:
441             fileFormat = FORMAT_NEW;
442             headerSize = 110;
443             break;
444         case FORMAT_NEW_CRC:
445             fileFormat = FORMAT_NEW_CRC;
446             headerSize = 110;
447             break;
448         case FORMAT_OLD_ASCII:
449             fileFormat = FORMAT_OLD_ASCII;
450             headerSize = 76;
451             break;
452         case FORMAT_OLD_BINARY:
453             fileFormat = FORMAT_OLD_BINARY;
454             headerSize = 26;
455             break;
456         default:
457             throw new IllegalArgumentException("Unknown header type");
458         }
459     }
460 
461     /***
462      * Set the group id.
463      * 
464      * @param gid The group id to set.
465      */
466     public void setGID(long gid) {
467         this.gid = gid;
468     }
469 
470     /***
471      * Set the inode.
472      * 
473      * @param inode The inode to set.
474      */
475     public void setInode(long inode) {
476         this.inode = inode;
477     }
478 
479     /***
480      * Set the mode of this entry (e.g. directory, regular file).
481      * 
482      * @param mode The mode to set.
483      */
484     public void setMode(long mode) {
485         switch ((int) (mode & S_IFMT)) {
486         case C_ISDIR:
487         case C_ISLNK:
488         case C_ISREG:
489         case C_ISFIFO:
490         case C_ISCHR:
491         case C_ISBLK:
492         case C_ISSOCK:
493         case C_ISNWK:
494             break;
495         default:
496             new IllegalArgumentException("Unknown mode");
497         }
498 
499         this.mode = mode;
500     }
501 
502     /***
503      * Set the name.
504      * 
505      * @param name The name to set.
506      */
507     public void setName(String name) {
508         this.name = name;
509     }
510 
511     /***
512      * Set the number of links.
513      * 
514      * @param nlink The number of links to set.
515      */
516     public void setNumberOfLinks(long nlink) {
517         this.nlink = nlink;
518     }
519 
520     /***
521      * Set the remote device id.
522      * 
523      * @param device The remote device id to set.
524      * @throws UnsupportedOperationException if this method is called
525      *            for a CPIOEntry with a new format.
526      */
527     public void setRemoteDevice(long device) {
528         checkOldFormat();
529         this.rmin = device;
530     }
531 
532     /***
533      * Set the remote major device id.
534      * 
535      * @param rmaj The remote major device id to set.
536      * @throws UnsupportedOperationException if this method is called
537      *            for a CPIOEntry with an old format.
538      */
539     public void setRemoteDeviceMaj(long rmaj) {
540         checkNewFormat();
541         this.rmaj = rmaj;
542     }
543 
544     /***
545      * Set the remote minor device id.
546      * 
547      * @param rmin The remote minor device id to set.
548      * @throws UnsupportedOperationException if this method is called
549      *            for a CPIOEntry with an old format.
550      */
551     public void setRemoteDeviceMin(long rmin) {
552         checkNewFormat();
553         this.rmin = rmin;
554     }
555 
556     /***
557      * Set the time in seconds.
558      * 
559      * @param time The time to set.
560      */
561     public void setTime(long time) {
562         this.mtime = time;
563     }
564 
565     /***
566      * Set the user id.
567      * 
568      * @param uid The user id to set.
569      */
570     public void setUID(long uid) {
571         this.uid = uid;
572     }
573 }