/** * This method, like getNameBytes(), is intended to place a name into a TarHeader's buffer. * However, this method is sophisticated enough to recognize long names (name.length() > NAMELEN). * In these cases, the method will break the name into a prefix and suffix and place the name in * the header in 'ustar' format. It is up to the TarEntry to manage the "entry header format". * This method assumes the name is valid for the type of archive being generated. * * @param outbuf The buffer containing the entry header to modify. * @param newName The new name to place into the header buffer. * @return The current offset in the tar header (always TarHeader.NAMELEN). * @throws InvalidHeaderException If the name will not fit in the header. */ public static int getFileNameBytes(String newName, byte[] outbuf) throws InvalidHeaderException { if (newName.length() > 100) { // Locate a pathname "break" prior to the maximum name length... int index = newName.indexOf("/", newName.length() - 100); if (index == -1) throw new InvalidHeaderException("file name is greater than 100 characters, " + newName); // Get the "suffix subpath" of the name. String name = newName.substring(index + 1); // Get the "prefix subpath", or "prefix", of the name. String prefix = newName.substring(0, index); if (prefix.length() > TarHeader.PREFIXLEN) throw new InvalidHeaderException("file prefix is greater than 155 characters"); TarHeader.getNameBytes( new StringBuffer(name), outbuf, TarHeader.NAMEOFFSET, TarHeader.NAMELEN); TarHeader.getNameBytes( new StringBuffer(prefix), outbuf, TarHeader.PREFIXOFFSET, TarHeader.PREFIXLEN); } else { TarHeader.getNameBytes( new StringBuffer(newName), outbuf, TarHeader.NAMEOFFSET, TarHeader.NAMELEN); } // The offset, regardless of the format, is now the end of the // original name field. // return TarHeader.NAMELEN; }
/** * Parse the checksum octal integer from a header buffer. * * @param header The header buffer from which to parse. * @param offset The offset into the buffer from which to parse. * @param length The number of header bytes to parse. * @return The integer value of the entry's checksum. */ public static int getCheckSumOctalBytes(long value, byte[] buf, int offset, int length) { TarHeader.getOctalBytes(value, buf, offset, length); buf[offset + length - 1] = (byte) ' '; buf[offset + length - 2] = 0; return offset + length; }
/** * Parse an octal long integer from a header buffer. * * @param header The header buffer from which to parse. * @param offset The offset into the buffer from which to parse. * @param length The number of header bytes to parse. * @return The long value of the octal bytes. */ public static int getLongOctalBytes(long value, byte[] buf, int offset, int length) { byte[] temp = new byte[length + 1]; TarHeader.getOctalBytes(value, temp, 0, length + 1); System.arraycopy(temp, 0, buf, offset, length); return offset + length; }
/** TarHeaders can be cloned. */ public Object clone() { TarHeader hdr = null; try { hdr = (TarHeader) super.clone(); hdr.name = (this.name == null) ? null : new StringBuffer(this.name.toString()); hdr.mode = this.mode; hdr.userId = this.userId; hdr.groupId = this.groupId; hdr.size = this.size; hdr.modTime = this.modTime; hdr.checkSum = this.checkSum; hdr.linkFlag = this.linkFlag; hdr.linkName = (this.linkName == null) ? null : new StringBuffer(this.linkName.toString()); hdr.magic = (this.magic == null) ? null : new StringBuffer(this.magic.toString()); hdr.userName = (this.userName == null) ? null : new StringBuffer(this.userName.toString()); hdr.groupName = (this.groupName == null) ? null : new StringBuffer(this.groupName.toString()); hdr.devMajor = this.devMajor; hdr.devMinor = this.devMinor; } catch (CloneNotSupportedException ex) { ex.printStackTrace(System.err); } return hdr; }
/** * Fill in a TarHeader given only the entry's name. * * @param hdr The TarHeader to fill in. * @param name The tar entry name. */ public void nameTarHeader(TarHeader hdr, String name) { boolean isDir = name.endsWith("/"); this.gnuFormat = false; this.ustarFormat = true; this.unixFormat = false; hdr.checkSum = 0; hdr.devMajor = 0; hdr.devMinor = 0; hdr.name = new StringBuffer(name); hdr.mode = isDir ? 040755 : 0100644; hdr.userId = 0; hdr.groupId = 0; hdr.size = 0; hdr.checkSum = 0; hdr.modTime = (new java.util.Date()).getTime() / 1000; hdr.linkFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL; hdr.linkName = new StringBuffer(""); hdr.userName = new StringBuffer(""); hdr.groupName = new StringBuffer(""); hdr.devMajor = 0; hdr.devMinor = 0; }
/** * Parse an entry's TarHeader information from a header buffer. * * <p>Old unix-style code contributed by David Mehringer <*****@*****.**>. * * @param hdr The TarHeader to fill in from the buffer information. * @param header The tar entry header buffer to get information from. */ public void parseTarHeader(TarHeader hdr, byte[] headerBuf) throws InvalidHeaderException { int offset = 0; // // NOTE Recognize archive header format. // if (headerBuf[257] == 0 && headerBuf[258] == 0 && headerBuf[259] == 0 && headerBuf[260] == 0 && headerBuf[261] == 0) { this.unixFormat = true; this.ustarFormat = false; this.gnuFormat = false; } else if (headerBuf[257] == 'u' && headerBuf[258] == 's' && headerBuf[259] == 't' && headerBuf[260] == 'a' && headerBuf[261] == 'r' && headerBuf[262] == 0) { this.ustarFormat = true; this.gnuFormat = false; this.unixFormat = false; } else if (headerBuf[257] == 'u' && headerBuf[258] == 's' && headerBuf[259] == 't' && headerBuf[260] == 'a' && headerBuf[261] == 'r' && headerBuf[262] != 0 && headerBuf[263] != 0) { // REVIEW this.gnuFormat = true; this.unixFormat = false; this.ustarFormat = false; } else { StringBuffer buf = new StringBuffer(128); buf.append("header magic is not 'ustar' or unix-style zeros, it is '"); buf.append(headerBuf[257]); buf.append(headerBuf[258]); buf.append(headerBuf[259]); buf.append(headerBuf[260]); buf.append(headerBuf[261]); buf.append(headerBuf[262]); buf.append(headerBuf[263]); buf.append("', or (dec) "); buf.append((int) headerBuf[257]); buf.append(", "); buf.append((int) headerBuf[258]); buf.append(", "); buf.append((int) headerBuf[259]); buf.append(", "); buf.append((int) headerBuf[260]); buf.append(", "); buf.append((int) headerBuf[261]); buf.append(", "); buf.append((int) headerBuf[262]); buf.append(", "); buf.append((int) headerBuf[263]); throw new InvalidHeaderException(buf.toString()); } hdr.name = TarHeader.parseFileName(headerBuf); offset = TarHeader.NAMELEN; hdr.mode = (int) TarHeader.parseOctal(headerBuf, offset, TarHeader.MODELEN); offset += TarHeader.MODELEN; hdr.userId = (int) TarHeader.parseOctal(headerBuf, offset, TarHeader.UIDLEN); offset += TarHeader.UIDLEN; hdr.groupId = (int) TarHeader.parseOctal(headerBuf, offset, TarHeader.GIDLEN); offset += TarHeader.GIDLEN; hdr.size = TarHeader.parseOctal(headerBuf, offset, TarHeader.SIZELEN); offset += TarHeader.SIZELEN; hdr.modTime = TarHeader.parseOctal(headerBuf, offset, TarHeader.MODTIMELEN); offset += TarHeader.MODTIMELEN; hdr.checkSum = (int) TarHeader.parseOctal(headerBuf, offset, TarHeader.CHKSUMLEN); offset += TarHeader.CHKSUMLEN; hdr.linkFlag = headerBuf[offset++]; hdr.linkName = TarHeader.parseName(headerBuf, offset, TarHeader.NAMELEN); offset += TarHeader.NAMELEN; if (this.ustarFormat) { hdr.magic = TarHeader.parseName(headerBuf, offset, TarHeader.MAGICLEN); offset += TarHeader.MAGICLEN; hdr.userName = TarHeader.parseName(headerBuf, offset, TarHeader.UNAMELEN); offset += TarHeader.UNAMELEN; hdr.groupName = TarHeader.parseName(headerBuf, offset, TarHeader.GNAMELEN); offset += TarHeader.GNAMELEN; hdr.devMajor = (int) TarHeader.parseOctal(headerBuf, offset, TarHeader.DEVLEN); offset += TarHeader.DEVLEN; hdr.devMinor = (int) TarHeader.parseOctal(headerBuf, offset, TarHeader.DEVLEN); } else { hdr.devMajor = 0; hdr.devMinor = 0; hdr.magic = new StringBuffer(""); hdr.userName = new StringBuffer(""); hdr.groupName = new StringBuffer(""); } }
/** * Write an entry's header information to a header buffer. This method can throw an * InvalidHeaderException * * @param outbuf The tar entry header buffer to fill in. * @throws InvalidHeaderException If the name will not fit in the header. */ public void writeEntryHeader(byte[] outbuf) throws InvalidHeaderException { int offset = 0; if (this.isUnixTarFormat()) { if (this.header.name.length() > 100) { throw new InvalidHeaderException( "file path is greater than 100 characters, " + this.header.name); } } offset = TarHeader.getFileNameBytes(this.header.name.toString(), outbuf); offset = TarHeader.getOctalBytes(this.header.mode, outbuf, offset, TarHeader.MODELEN); offset = TarHeader.getOctalBytes(this.header.userId, outbuf, offset, TarHeader.UIDLEN); offset = TarHeader.getOctalBytes(this.header.groupId, outbuf, offset, TarHeader.GIDLEN); long size = this.header.size; offset = TarHeader.getLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN); offset = TarHeader.getLongOctalBytes(this.header.modTime, outbuf, offset, TarHeader.MODTIMELEN); int csOffset = offset; for (int c = 0; c < TarHeader.CHKSUMLEN; ++c) { outbuf[offset++] = (byte) ' '; } outbuf[offset++] = this.header.linkFlag; offset = TarHeader.getNameBytes(this.header.linkName, outbuf, offset, TarHeader.NAMELEN); if (this.unixFormat) { for (int i = 0; i < TarHeader.MAGICLEN; ++i) { outbuf[offset++] = 0; } } else { offset = TarHeader.getNameBytes(this.header.magic, outbuf, offset, TarHeader.MAGICLEN); } offset = TarHeader.getNameBytes(this.header.userName, outbuf, offset, TarHeader.UNAMELEN); offset = TarHeader.getNameBytes(this.header.groupName, outbuf, offset, TarHeader.GNAMELEN); offset = TarHeader.getOctalBytes(this.header.devMajor, outbuf, offset, TarHeader.DEVLEN); offset = TarHeader.getOctalBytes(this.header.devMinor, outbuf, offset, TarHeader.DEVLEN); for (; offset < outbuf.length; ) { outbuf[offset++] = 0; } long checkSum = this.computeCheckSum(outbuf); TarHeader.getCheckSumOctalBytes(checkSum, outbuf, csOffset, TarHeader.CHKSUMLEN); }
/** * Fill in a TarHeader with information from a File. * * @param hdr The TarHeader to fill in. * @param file The file from which to get the header information. */ public void getFileTarHeader(TarHeader hdr, File file) throws InvalidHeaderException { this.file = file; String name = file.getPath(); String osname = System.getProperty("os.name"); if (osname != null) { // Strip off drive letters! // REVIEW Would a better check be "(File.separator == '\')"? // String Win32Prefix = "Windows"; // String prefix = osname.substring( 0, Win32Prefix.length() ); // if ( prefix.equalsIgnoreCase( Win32Prefix ) ) // if ( File.separatorChar == '\\' ) // Windows OS check was contributed by // Patrick Beard <*****@*****.**> String Win32Prefix = "windows"; if (osname.toLowerCase().startsWith(Win32Prefix)) { if (name.length() > 2) { char ch1 = name.charAt(0); char ch2 = name.charAt(1); if (ch2 == ':' && ((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z'))) { name = name.substring(2); } } } } name = name.replace(File.separatorChar, '/'); // No absolute pathnames // Windows (and Posix?) paths can start with "\\NetworkDrive\", // so we loop on starting /'s. for (; name.startsWith("/"); ) { name = name.substring(1); } hdr.linkName = new StringBuffer(""); hdr.name = new StringBuffer(name); if (file.isDirectory()) { hdr.size = 0; hdr.mode = 040755; hdr.linkFlag = TarHeader.LF_DIR; if (hdr.name.charAt(hdr.name.length() - 1) != '/') { hdr.name.append("/"); } } else { hdr.size = file.length(); hdr.mode = 0100644; hdr.linkFlag = TarHeader.LF_NORMAL; } // UNDONE When File lets us get the userName, use it! hdr.modTime = file.lastModified() / 1000; hdr.checkSum = 0; hdr.devMajor = 0; hdr.devMinor = 0; }