Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 614   Methods: 33
NCLOC: 260   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
TarEntry.java 44.1% 73.2% 48.5% 65%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 
 55   
 /*
 56   
  * This package is based on the work done by Timothy Gerard Endres 
 57   
  * (time@ice.com) to whom the Ant project is very grateful for his great code.
 58   
  */
 59   
 
 60   
 package org.apache.tools.tar;
 61   
 
 62   
 import java.io.File;
 63   
 import java.util.Date;
 64   
 import java.util.Locale;
 65   
 
 66   
 /**
 67   
  * This class represents an entry in a Tar archive. It consists
 68   
  * of the entry's header, as well as the entry's File. Entries
 69   
  * can be instantiated in one of three ways, depending on how
 70   
  * they are to be used.
 71   
  * <p>
 72   
  * TarEntries that are created from the header bytes read from
 73   
  * an archive are instantiated with the TarEntry( byte[] )
 74   
  * constructor. These entries will be used when extracting from
 75   
  * or listing the contents of an archive. These entries have their
 76   
  * header filled in using the header bytes. They also set the File
 77   
  * to null, since they reference an archive entry not a file.
 78   
  * <p>
 79   
  * TarEntries that are created from Files that are to be written
 80   
  * into an archive are instantiated with the TarEntry( File )
 81   
  * constructor. These entries have their header filled in using
 82   
  * the File's information. They also keep a reference to the File
 83   
  * for convenience when writing entries.
 84   
  * <p>
 85   
  * Finally, TarEntries can be constructed from nothing but a name.
 86   
  * This allows the programmer to construct the entry by hand, for
 87   
  * instance when only an InputStream is available for writing to
 88   
  * the archive, and the header information is constructed from
 89   
  * other information. In this case the header fields are set to
 90   
  * defaults and the File is set to null.
 91   
  * 
 92   
  * <p>
 93   
  * The C structure for a Tar Entry's header is:
 94   
  * <pre>
 95   
  * struct header {
 96   
  * char name[NAMSIZ];
 97   
  * char mode[8];
 98   
  * char uid[8];
 99   
  * char gid[8];
 100   
  * char size[12];
 101   
  * char mtime[12];
 102   
  * char chksum[8];
 103   
  * char linkflag;
 104   
  * char linkname[NAMSIZ];
 105   
  * char magic[8];
 106   
  * char uname[TUNMLEN];
 107   
  * char gname[TGNMLEN];
 108   
  * char devmajor[8];
 109   
  * char devminor[8];
 110   
  * } header;
 111   
  * </pre>
 112   
  * 
 113   
  * @author Timothy Gerard Endres <a href="mailto:time@ice.com">time@ice.com</a>
 114   
  * @author Stefano Mazzocchi <a href="mailto:stefano@apache.org">stefano@apache.org</a>
 115   
  */
 116   
  
 117   
 public class TarEntry implements TarConstants {
 118   
 
 119   
     private StringBuffer name;      /** The entry's name. */
 120   
     private int          mode;      /** The entry's permission mode. */
 121   
     private int          userId;    /** The entry's user id. */
 122   
     private int          groupId;   /** The entry's group id. */
 123   
     private long         size;      /** The entry's size. */
 124   
     private long         modTime;   /** The entry's modification time. */
 125   
     private int          checkSum;  /** The entry's checksum. */
 126   
     private byte         linkFlag;  /** The entry's link flag. */
 127   
     private StringBuffer linkName;  /** The entry's link name. */
 128   
     private StringBuffer magic;     /** The entry's magic tag. */
 129   
     private StringBuffer userName;  /** The entry's user name. */
 130   
     private StringBuffer groupName; /** The entry's group name. */
 131   
     private int          devMajor;  /** The entry's major device number. */
 132   
     private int          devMinor;  /** The entry's minor device number. */
 133   
     private File         file;      /** The entry's file reference */ 
 134   
 
 135   
     /** 
 136   
      * Construct an empty entry and prepares the header values.
 137   
      */ 
 138  27
     private TarEntry () {
 139  27
         this.magic = new StringBuffer(TMAGIC);
 140  27
         this.name = new StringBuffer();
 141  27
         this.linkName = new StringBuffer();
 142   
     
 143  27
         String user = System.getProperty("user.name", "");
 144   
     
 145  27
         if (user.length() > 31) {
 146  0
             user = user.substring(0, 31);
 147   
         } 
 148   
     
 149  27
         this.userId = 0;
 150  27
         this.groupId = 0;
 151  27
         this.userName = new StringBuffer(user);
 152  27
         this.groupName = new StringBuffer("");
 153  27
         this.file = null;
 154   
     }
 155   
         
 156   
     /** 
 157   
      * Construct an entry with only a name. This allows the programmer
 158   
      * to construct the entry's header "by hand". File is set to null.
 159   
      */ 
 160  15
     public TarEntry(String name) {
 161  15
         this();
 162   
         
 163  15
         boolean isDir = name.endsWith("/");
 164   
         
 165  15
         this.checkSum = 0;
 166  15
         this.devMajor = 0;
 167  15
         this.devMinor = 0;
 168  15
         this.name = new StringBuffer(name);
 169  15
         this.mode = isDir ? 040755 : 0100644;
 170  15
         this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
 171  15
         this.userId = 0;
 172  15
         this.groupId = 0;
 173  15
         this.size = 0;
 174  15
         this.checkSum = 0;
 175  15
         this.modTime = (new Date()).getTime() / 1000;
 176  15
         this.linkName = new StringBuffer("");
 177  15
         this.userName = new StringBuffer("");
 178  15
         this.groupName = new StringBuffer("");
 179  15
         this.devMajor = 0;
 180  15
         this.devMinor = 0;
 181   
 
 182   
     }   
 183   
         
 184   
     /** 
 185   
      * Construct an entry with a name an a link flag.
 186   
      */ 
 187  0
     public TarEntry(String name, byte linkFlag) {
 188  0
         this(name);
 189  0
         this.linkFlag = linkFlag;
 190   
     }   
 191   
         
 192   
     /** 
 193   
      * Construct an entry for a file. File is set to file, and the
 194   
      * header is constructed from information from the file.
 195   
      *  
 196   
      * @param file The file that the entry represents.
 197   
      */ 
 198  1
     public TarEntry(File file) {
 199  1
         this();
 200   
         
 201  1
         this.file = file;
 202   
         
 203  1
         String name = file.getPath();
 204  1
         String osname = System.getProperty("os.name").toLowerCase(Locale.US);
 205   
         
 206  1
         if (osname != null) {
 207   
         
 208   
             // Strip off drive letters!
 209   
             // REVIEW Would a better check be "(File.separator == '\')"?
 210   
         
 211  1
             if (osname.startsWith("windows")) {
 212  0
                 if (name.length() > 2) {
 213  0
                     char ch1 = name.charAt(0);
 214  0
                     char ch2 = name.charAt(1);
 215   
         
 216  0
                     if (ch2 == ':' 
 217   
                             && ((ch1 >= 'a' && ch1 <= 'z') 
 218   
                                 || (ch1 >= 'A' && ch1 <= 'Z'))) {
 219  0
                         name = name.substring(2);
 220   
                     } 
 221   
                 } 
 222  1
             } else if (osname.indexOf("netware") > -1) {
 223  0
                 int colon = name.indexOf(':');
 224  0
                 if (colon != -1) {
 225  0
                     name = name.substring(colon + 1);
 226   
                 }
 227   
             }
 228   
         } 
 229   
         
 230  1
         name = name.replace(File.separatorChar, '/');
 231   
         
 232   
         // No absolute pathnames
 233   
         // Windows (and Posix?) paths can start with "\\NetworkDrive\",
 234   
         // so we loop on starting /'s.
 235  1
         while (name.startsWith("/")) {
 236  1
             name = name.substring(1);
 237   
         }
 238   
         
 239  1
         this.linkName = new StringBuffer("");
 240  1
         this.name = new StringBuffer(name);
 241   
         
 242  1
         if (file.isDirectory()) {
 243  0
             this.mode = 040755;
 244  0
             this.linkFlag = LF_DIR;
 245   
         
 246  0
             if (this.name.charAt(this.name.length() - 1) != '/') {
 247  0
                 this.name.append("/");
 248   
             } 
 249   
         } else {
 250  1
             this.mode = 0100644;
 251  1
             this.linkFlag = LF_NORMAL;
 252   
         } 
 253   
         
 254  1
         this.size = file.length();
 255  1
         this.modTime = file.lastModified() / 1000;
 256  1
         this.checkSum = 0;
 257  1
         this.devMajor = 0;
 258  1
         this.devMinor = 0;
 259   
     }   
 260   
         
 261   
     /** 
 262   
      * Construct an entry from an archive's header bytes. File is set
 263   
      * to null.
 264   
      *  
 265   
      * @param headerBuf The header bytes from a tar archive entry.
 266   
      */ 
 267  11
     public TarEntry(byte[] headerBuf) {
 268  11
         this();
 269  11
         this.parseTarHeader(headerBuf);
 270   
     }   
 271   
         
 272   
     /** 
 273   
      * Determine if the two entries are equal. Equality is determined
 274   
      * by the header names being equal.
 275   
      *  
 276   
      * @return it Entry to be checked for equality.
 277   
      * @return True if the entries are equal.
 278   
      */ 
 279  0
     public boolean equals(TarEntry it) {
 280  0
         return this.getName().equals(it.getName());
 281   
     }   
 282   
         
 283   
     /** 
 284   
      * Determine if the given entry is a descendant of this entry.
 285   
      * Descendancy is determined by the name of the descendant
 286   
      * starting with this entry's name.
 287   
      *  
 288   
      * @param desc Entry to be checked as a descendent of this.
 289   
      * @return True if entry is a descendant of this.
 290   
      */ 
 291  0
     public boolean isDescendent(TarEntry desc) {
 292  0
         return desc.getName().startsWith(this.getName());
 293   
     }   
 294   
         
 295   
     /** 
 296   
      * Get this entry's name.
 297   
      *  
 298   
      * @return This entry's name.
 299   
      */ 
 300  47
     public String getName() {
 301  47
         return this.name.toString();
 302   
     }   
 303   
         
 304   
     /** 
 305   
      * Set this entry's name.
 306   
      *  
 307   
      * @param name This entry's new name.
 308   
      */ 
 309  0
     public void setName(String name) {
 310  0
         this.name = new StringBuffer(name);
 311   
     }   
 312   
 
 313   
     /**
 314   
      * Set the mode for this entry
 315   
      */
 316  15
     public void setMode(int mode) {
 317  15
         this.mode = mode;
 318   
     }
 319   
 
 320   
     /**
 321   
      * Get this entry's link name.
 322   
      *
 323   
      * @return This entry's link name.
 324   
      */
 325  0
     public String getLinkName() {
 326  0
         return this.linkName.toString();
 327   
     }
 328   
 
 329   
     /** 
 330   
      * Get this entry's user id.
 331   
      *  
 332   
      * @return This entry's user id.
 333   
      */ 
 334  0
     public int getUserId() {
 335  0
         return this.userId;
 336   
     }   
 337   
         
 338   
     /** 
 339   
      * Set this entry's user id.
 340   
      *  
 341   
      * @param userId This entry's new user id.
 342   
      */ 
 343  0
     public void setUserId(int userId) {
 344  0
         this.userId = userId;
 345   
     }   
 346   
         
 347   
     /** 
 348   
      * Get this entry's group id.
 349   
      *  
 350   
      * @return This entry's group id.
 351   
      */ 
 352  0
     public int getGroupId() {
 353  0
         return this.groupId;
 354   
     }   
 355   
         
 356   
     /** 
 357   
      * Set this entry's group id.
 358   
      *  
 359   
      * @param groupId This entry's new group id.
 360   
      */ 
 361  0
     public void setGroupId(int groupId) {
 362  0
         this.groupId = groupId;
 363   
     }   
 364   
         
 365   
     /** 
 366   
      * Get this entry's user name.
 367   
      *  
 368   
      * @return This entry's user name.
 369   
      */ 
 370  0
     public String getUserName() {
 371  0
         return this.userName.toString();
 372   
     }   
 373   
         
 374   
     /** 
 375   
      * Set this entry's user name.
 376   
      *  
 377   
      * @param userName This entry's new user name.
 378   
      */ 
 379  15
     public void setUserName(String userName) {
 380  15
         this.userName = new StringBuffer(userName);
 381   
     }   
 382   
         
 383   
     /** 
 384   
      * Get this entry's group name.
 385   
      *  
 386   
      * @return This entry's group name.
 387   
      */ 
 388  0
     public String getGroupName() {
 389  0
         return this.groupName.toString();
 390   
     }   
 391   
         
 392   
     /** 
 393   
      * Set this entry's group name.
 394   
      *  
 395   
      * @param groupName This entry's new group name.
 396   
      */ 
 397  15
     public void setGroupName(String groupName) {
 398  15
         this.groupName = new StringBuffer(groupName);
 399   
     }   
 400   
         
 401   
     /** 
 402   
      * Convenience method to set this entry's group and user ids.
 403   
      *  
 404   
      * @param userId This entry's new user id.
 405   
      * @param groupId This entry's new group id.
 406   
      */ 
 407  0
     public void setIds(int userId, int groupId) {
 408  0
         this.setUserId(userId);
 409  0
         this.setGroupId(groupId);
 410   
     }   
 411   
         
 412   
     /** 
 413   
      * Convenience method to set this entry's group and user names.
 414   
      *  
 415   
      * @param userName This entry's new user name.
 416   
      * @param groupName This entry's new group name.
 417   
      */ 
 418  0
     public void setNames(String userName, String groupName) {
 419  0
         this.setUserName(userName);
 420  0
         this.setGroupName(groupName);
 421   
     }   
 422   
         
 423   
     /** 
 424   
      * Set this entry's modification time. The parameter passed
 425   
      * to this method is in "Java time".
 426   
      *  
 427   
      * @param time This entry's new modification time.
 428   
      */ 
 429  15
     public void setModTime(long time) {
 430  15
         this.modTime = time / 1000;
 431   
     }   
 432   
         
 433   
     /** 
 434   
      * Set this entry's modification time.
 435   
      *  
 436   
      * @param time This entry's new modification time.
 437   
      */ 
 438  0
     public void setModTime(Date time) {
 439  0
         this.modTime = time.getTime() / 1000;
 440   
     }   
 441   
         
 442   
     /** 
 443   
      * Set this entry's modification time.
 444   
      *  
 445   
      * @param time This entry's new modification time.
 446   
      */ 
 447  11
     public Date getModTime() {
 448  11
         return new Date(this.modTime * 1000);
 449   
     }   
 450   
         
 451   
     /** 
 452   
      * Get this entry's file.
 453   
      *  
 454   
      * @return This entry's file.
 455   
      */ 
 456  0
     public File getFile() {
 457  0
         return this.file;
 458   
     }   
 459   
         
 460   
     /** 
 461   
      * Get this entry's mode.
 462   
      *
 463   
      * @return This entry's mode.
 464   
      */
 465  0
     public int getMode() {
 466  0
         return this.mode;
 467   
     }
 468   
 
 469   
     /**
 470   
      * Get this entry's file size.
 471   
      *  
 472   
      * @return This entry's file size.
 473   
      */ 
 474  23
     public long getSize() {
 475  23
         return this.size;
 476   
     }   
 477   
         
 478   
     /** 
 479   
      * Set this entry's file size.
 480   
      *  
 481   
      * @param size This entry's new file size.
 482   
      */ 
 483  12
     public void setSize(long size) {
 484  12
         this.size = size;
 485   
     }   
 486   
 
 487   
         
 488   
     /**
 489   
      * Indicate if this entry is a GNU long name block
 490   
      *
 491   
      * @return true if this is a long name extension provided by GNU tar
 492   
      */
 493  11
     public boolean isGNULongNameEntry() {
 494  11
         return linkFlag == LF_GNUTYPE_LONGNAME &&
 495   
                name.toString().equals(GNU_LONGLINK);
 496   
     }               
 497   
 
 498   
     /** 
 499   
      * Return whether or not this entry represents a directory.
 500   
      *  
 501   
      * @return True if this entry is a directory.
 502   
      */ 
 503  26
     public boolean isDirectory() {
 504  26
         if (this.file != null) {
 505  0
             return this.file.isDirectory();
 506   
         } 
 507   
         
 508  26
         if (this.linkFlag == LF_DIR) {
 509  5
             return true;
 510   
         } 
 511   
         
 512  21
         if (this.getName().endsWith("/")) {
 513  0
             return true;
 514   
         } 
 515   
         
 516  21
         return false;
 517   
     }   
 518   
         
 519   
     /** 
 520   
      * If this entry represents a file, and the file is a directory, return
 521   
      * an array of TarEntries for this entry's children.
 522   
      *  
 523   
      * @return An array of TarEntry's for this entry's children.
 524   
      */ 
 525  0
     public TarEntry[] getDirectoryEntries() {
 526  0
         if (this.file == null || !this.file.isDirectory()) {
 527  0
             return new TarEntry[0];
 528   
         } 
 529   
         
 530  0
         String[]   list = this.file.list();
 531  0
         TarEntry[] result = new TarEntry[list.length];
 532   
         
 533  0
         for (int i = 0; i < list.length; ++i) {
 534  0
             result[i] = new TarEntry(new File(this.file, list[i]));
 535   
         } 
 536   
         
 537  0
         return result;
 538   
     }   
 539   
         
 540   
     /** 
 541   
      * Write an entry's header information to a header buffer.
 542   
      *  
 543   
      * @param outbuf The tar entry header buffer to fill in.
 544   
      */ 
 545  15
     public void writeEntryHeader(byte[] outbuf) {
 546  15
         int offset = 0;
 547   
         
 548  15
         offset = TarUtils.getNameBytes(this.name, outbuf, offset, NAMELEN);
 549  15
         offset = TarUtils.getOctalBytes(this.mode, outbuf, offset, MODELEN);
 550  15
         offset = TarUtils.getOctalBytes(this.userId, outbuf, offset, UIDLEN);
 551  15
         offset = TarUtils.getOctalBytes(this.groupId, outbuf, offset, GIDLEN);
 552  15
         offset = TarUtils.getLongOctalBytes(this.size, outbuf, offset, SIZELEN);
 553  15
         offset = TarUtils.getLongOctalBytes(this.modTime, outbuf, offset, MODTIMELEN);
 554   
         
 555  15
         int csOffset = offset;
 556   
         
 557  15
         for (int c = 0; c < CHKSUMLEN; ++c) {
 558  120
             outbuf[offset++] = (byte) ' ';
 559   
         }
 560   
         
 561  15
         outbuf[offset++] = this.linkFlag;
 562  15
         offset = TarUtils.getNameBytes(this.linkName, outbuf, offset, NAMELEN);
 563  15
         offset = TarUtils.getNameBytes(this.magic, outbuf, offset, MAGICLEN);
 564  15
         offset = TarUtils.getNameBytes(this.userName, outbuf, offset, UNAMELEN);
 565  15
         offset = TarUtils.getNameBytes(this.groupName, outbuf, offset, GNAMELEN);
 566  15
         offset = TarUtils.getOctalBytes(this.devMajor, outbuf, offset, DEVLEN);
 567  15
         offset = TarUtils.getOctalBytes(this.devMinor, outbuf, offset, DEVLEN);
 568   
         
 569  15
         while (offset < outbuf.length) {
 570  2505
             outbuf[offset++] = 0;
 571   
         }
 572   
         
 573  15
         long checkSum = TarUtils.computeCheckSum(outbuf);
 574   
         
 575  15
         TarUtils.getCheckSumOctalBytes(checkSum, outbuf, csOffset, CHKSUMLEN);
 576   
     }   
 577   
         
 578   
     /** 
 579   
      * Parse an entry's header information from a header buffer.
 580   
      *  
 581   
      * @param header The tar entry header buffer to get information from.
 582   
      */ 
 583  11
     public void parseTarHeader(byte[] header) {
 584  11
         int offset = 0;
 585   
         
 586  11
         this.name = TarUtils.parseName(header, offset, NAMELEN);  
 587  11
         offset += NAMELEN;
 588  11
         this.mode = (int) TarUtils.parseOctal(header, offset, MODELEN); 
 589  11
         offset += MODELEN;
 590  11
         this.userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
 591  11
         offset += UIDLEN;
 592  11
         this.groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
 593  11
         offset += GIDLEN;
 594  11
         this.size = TarUtils.parseOctal(header, offset, SIZELEN);
 595  11
         offset += SIZELEN;
 596  11
         this.modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
 597  11
         offset += MODTIMELEN;
 598  11
         this.checkSum = (int) TarUtils.parseOctal(header, offset, CHKSUMLEN);
 599  11
         offset += CHKSUMLEN;
 600  11
         this.linkFlag = header[offset++];
 601  11
         this.linkName = TarUtils.parseName(header, offset, NAMELEN);
 602  11
         offset += NAMELEN;
 603  11
         this.magic = TarUtils.parseName(header, offset, MAGICLEN);
 604  11
         offset += MAGICLEN;
 605  11
         this.userName = TarUtils.parseName(header, offset, UNAMELEN);
 606  11
         offset += UNAMELEN;
 607  11
         this.groupName = TarUtils.parseName(header, offset, GNAMELEN);
 608  11
         offset += GNAMELEN;
 609  11
         this.devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
 610  11
         offset += DEVLEN;
 611  11
         this.devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
 612   
     }
 613   
 }       
 614