mirror of
https://github.com/topjohnwu/jtar.git
synced 2024-11-23 11:29:47 +00:00
Formating
This commit is contained in:
parent
4662a4286b
commit
219e8b25f1
@ -15,95 +15,95 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class PermissionUtils {
|
public class PermissionUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XXX: When using standard Java permissions, we treat 'owner' and 'group' equally and give no
|
* XXX: When using standard Java permissions, we treat 'owner' and 'group' equally and give no
|
||||||
* permissions for 'others'.
|
* permissions for 'others'.
|
||||||
*/
|
*/
|
||||||
private static enum StandardFilePermission {
|
private static enum StandardFilePermission {
|
||||||
EXECUTE(0110), WRITE(0220), READ(0440);
|
EXECUTE(0110), WRITE(0220), READ(0440);
|
||||||
|
|
||||||
private int mode;
|
private int mode;
|
||||||
|
|
||||||
private StandardFilePermission(int mode) {
|
private StandardFilePermission(int mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<PosixFilePermission, Integer> posixPermissionToInteger = new HashMap<>();
|
private static Map<PosixFilePermission, Integer> posixPermissionToInteger = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
posixPermissionToInteger.put(PosixFilePermission.OWNER_EXECUTE, 0100);
|
posixPermissionToInteger.put(PosixFilePermission.OWNER_EXECUTE, 0100);
|
||||||
posixPermissionToInteger.put(PosixFilePermission.OWNER_WRITE, 0200);
|
posixPermissionToInteger.put(PosixFilePermission.OWNER_WRITE, 0200);
|
||||||
posixPermissionToInteger.put(PosixFilePermission.OWNER_READ, 0400);
|
posixPermissionToInteger.put(PosixFilePermission.OWNER_READ, 0400);
|
||||||
|
|
||||||
posixPermissionToInteger.put(PosixFilePermission.GROUP_EXECUTE, 0010);
|
posixPermissionToInteger.put(PosixFilePermission.GROUP_EXECUTE, 0010);
|
||||||
posixPermissionToInteger.put(PosixFilePermission.GROUP_WRITE, 0020);
|
posixPermissionToInteger.put(PosixFilePermission.GROUP_WRITE, 0020);
|
||||||
posixPermissionToInteger.put(PosixFilePermission.GROUP_READ, 0040);
|
posixPermissionToInteger.put(PosixFilePermission.GROUP_READ, 0040);
|
||||||
|
|
||||||
posixPermissionToInteger.put(PosixFilePermission.OTHERS_EXECUTE, 0001);
|
posixPermissionToInteger.put(PosixFilePermission.OTHERS_EXECUTE, 0001);
|
||||||
posixPermissionToInteger.put(PosixFilePermission.OTHERS_WRITE, 0002);
|
posixPermissionToInteger.put(PosixFilePermission.OTHERS_WRITE, 0002);
|
||||||
posixPermissionToInteger.put(PosixFilePermission.OTHERS_READ, 0004);
|
posixPermissionToInteger.put(PosixFilePermission.OTHERS_READ, 0004);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get file permissions in octal mode, e.g. 0755.
|
* Get file permissions in octal mode, e.g. 0755.
|
||||||
*
|
*
|
||||||
* Note: it uses `java.nio.file.attribute.PosixFilePermission` if OS supports this, otherwise reverts to
|
* Note: it uses `java.nio.file.attribute.PosixFilePermission` if OS supports this, otherwise reverts to
|
||||||
* using standard Java file operations, e.g. `java.io.File#canExecute()`. In the first case permissions will
|
* using standard Java file operations, e.g. `java.io.File#canExecute()`. In the first case permissions will
|
||||||
* be precisely as reported by the OS, in the second case 'owner' and 'group' will have equal permissions and
|
* be precisely as reported by the OS, in the second case 'owner' and 'group' will have equal permissions and
|
||||||
* 'others' will have no permissions, e.g. if file on Windows OS is `read-only` permissions will be `0550`.
|
* 'others' will have no permissions, e.g. if file on Windows OS is `read-only` permissions will be `0550`.
|
||||||
*
|
*
|
||||||
* @throws NullPointerException if file is null.
|
* @throws NullPointerException if file is null.
|
||||||
* @throws IllegalArgumentException if file does not exist.
|
* @throws IllegalArgumentException if file does not exist.
|
||||||
*/
|
*/
|
||||||
public static int permissions(File f) {
|
public static int permissions(File f) {
|
||||||
if(f == null) {
|
if(f == null) {
|
||||||
throw new NullPointerException("File is null.");
|
throw new NullPointerException("File is null.");
|
||||||
}
|
}
|
||||||
if(!f.exists()) {
|
if(!f.exists()) {
|
||||||
throw new IllegalArgumentException("File " + f + " does not exist.");
|
throw new IllegalArgumentException("File " + f + " does not exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return isPosix ? posixPermissions(f) : standardPermissions(f);
|
return isPosix ? posixPermissions(f) : standardPermissions(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
||||||
|
|
||||||
private static int posixPermissions(File f) {
|
private static int posixPermissions(File f) {
|
||||||
int number = 0;
|
int number = 0;
|
||||||
try {
|
try {
|
||||||
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(f.toPath());
|
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(f.toPath());
|
||||||
for (Map.Entry<PosixFilePermission, Integer> entry : posixPermissionToInteger.entrySet()) {
|
for (Map.Entry<PosixFilePermission, Integer> entry : posixPermissionToInteger.entrySet()) {
|
||||||
if (permissions.contains(entry.getKey())) {
|
if (permissions.contains(entry.getKey())) {
|
||||||
number += entry.getValue();
|
number += entry.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<StandardFilePermission> readStandardPermissions(File f) {
|
private static Set<StandardFilePermission> readStandardPermissions(File f) {
|
||||||
Set<StandardFilePermission> permissions = new HashSet<>();
|
Set<StandardFilePermission> permissions = new HashSet<>();
|
||||||
if(f.canExecute()) {
|
if(f.canExecute()) {
|
||||||
permissions.add(StandardFilePermission.EXECUTE);
|
permissions.add(StandardFilePermission.EXECUTE);
|
||||||
}
|
}
|
||||||
if(f.canWrite()) {
|
if(f.canWrite()) {
|
||||||
permissions.add(StandardFilePermission.WRITE);
|
permissions.add(StandardFilePermission.WRITE);
|
||||||
}
|
}
|
||||||
if(f.canRead()) {
|
if(f.canRead()) {
|
||||||
permissions.add(StandardFilePermission.READ);
|
permissions.add(StandardFilePermission.READ);
|
||||||
}
|
}
|
||||||
return permissions;
|
return permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Integer standardPermissions(File f) {
|
private static Integer standardPermissions(File f) {
|
||||||
int number = 0;
|
int number = 0;
|
||||||
Set<StandardFilePermission> permissions = readStandardPermissions(f);
|
Set<StandardFilePermission> permissions = readStandardPermissions(f);
|
||||||
for (StandardFilePermission permission : permissions) {
|
for (StandardFilePermission permission : permissions) {
|
||||||
number += permission.mode;
|
number += permission.mode;
|
||||||
}
|
}
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,256 +25,256 @@ import java.util.Date;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TarEntry {
|
public class TarEntry {
|
||||||
protected File file;
|
protected File file;
|
||||||
protected TarHeader header;
|
protected TarHeader header;
|
||||||
|
|
||||||
private TarEntry() {
|
private TarEntry() {
|
||||||
this.file = null;
|
this.file = null;
|
||||||
header = new TarHeader();
|
header = new TarHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TarEntry(File file, String entryName) {
|
public TarEntry(File file, String entryName) {
|
||||||
this();
|
this();
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.extractTarHeader(entryName);
|
this.extractTarHeader(entryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TarEntry(byte[] headerBuf) {
|
public TarEntry(byte[] headerBuf) {
|
||||||
this();
|
this();
|
||||||
this.parseTarHeader(headerBuf);
|
this.parseTarHeader(headerBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor to create an entry from an existing TarHeader object.
|
* Constructor to create an entry from an existing TarHeader object.
|
||||||
*
|
*
|
||||||
* This method is useful to add new entries programmatically (e.g. for
|
* This method is useful to add new entries programmatically (e.g. for
|
||||||
* adding files or directories that do not exist in the file system).
|
* adding files or directories that do not exist in the file system).
|
||||||
*/
|
*/
|
||||||
public TarEntry(TarHeader header) {
|
public TarEntry(TarHeader header) {
|
||||||
this.file = null;
|
this.file = null;
|
||||||
this.header = header;
|
this.header = header;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object it) {
|
public boolean equals(Object it) {
|
||||||
if (!(it instanceof TarEntry)) {
|
if (!(it instanceof TarEntry)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return header.name.toString().equals(
|
return header.name.toString().equals(
|
||||||
((TarEntry) it).header.name.toString());
|
((TarEntry) it).header.name.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return header.name.hashCode();
|
return header.name.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDescendent(TarEntry desc) {
|
public boolean isDescendent(TarEntry desc) {
|
||||||
return desc.header.name.toString().startsWith(header.name.toString());
|
return desc.header.name.toString().startsWith(header.name.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TarHeader getHeader() {
|
public TarHeader getHeader() {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
String name = header.name.toString();
|
String name = header.name.toString();
|
||||||
if (header.namePrefix != null && !header.namePrefix.toString().equals("")) {
|
if (header.namePrefix != null && !header.namePrefix.toString().equals("")) {
|
||||||
name = header.namePrefix.toString() + "/" + name;
|
name = header.namePrefix.toString() + "/" + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
header.name = new StringBuffer(name);
|
header.name = new StringBuffer(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getUserId() {
|
public int getUserId() {
|
||||||
return header.userId;
|
return header.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserId(int userId) {
|
public void setUserId(int userId) {
|
||||||
header.userId = userId;
|
header.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getGroupId() {
|
public int getGroupId() {
|
||||||
return header.groupId;
|
return header.groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroupId(int groupId) {
|
public void setGroupId(int groupId) {
|
||||||
header.groupId = groupId;
|
header.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserName() {
|
public String getUserName() {
|
||||||
return header.userName.toString();
|
return header.userName.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserName(String userName) {
|
public void setUserName(String userName) {
|
||||||
header.userName = new StringBuffer(userName);
|
header.userName = new StringBuffer(userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGroupName() {
|
public String getGroupName() {
|
||||||
return header.groupName.toString();
|
return header.groupName.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroupName(String groupName) {
|
public void setGroupName(String groupName) {
|
||||||
header.groupName = new StringBuffer(groupName);
|
header.groupName = new StringBuffer(groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIds(int userId, int groupId) {
|
public void setIds(int userId, int groupId) {
|
||||||
this.setUserId(userId);
|
this.setUserId(userId);
|
||||||
this.setGroupId(groupId);
|
this.setGroupId(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setModTime(long time) {
|
public void setModTime(long time) {
|
||||||
header.modTime = time / 1000;
|
header.modTime = time / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setModTime(Date time) {
|
public void setModTime(Date time) {
|
||||||
header.modTime = time.getTime() / 1000;
|
header.modTime = time.getTime() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getModTime() {
|
public Date getModTime() {
|
||||||
return new Date(header.modTime * 1000);
|
return new Date(header.modTime * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
return this.file;
|
return this.file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return header.size;
|
return header.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSize(long size) {
|
public void setSize(long size) {
|
||||||
header.size = size;
|
header.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the org.kamrazafar.jtar entry is a directory
|
* Checks if the org.kamrazafar.jtar entry is a directory
|
||||||
*/
|
*/
|
||||||
public boolean isDirectory() {
|
public boolean isDirectory() {
|
||||||
if (this.file != null)
|
if (this.file != null)
|
||||||
return this.file.isDirectory();
|
return this.file.isDirectory();
|
||||||
|
|
||||||
if (header != null) {
|
if (header != null) {
|
||||||
if (header.linkFlag == TarHeader.LF_DIR)
|
if (header.linkFlag == TarHeader.LF_DIR)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (header.name.toString().endsWith("/"))
|
if (header.name.toString().endsWith("/"))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract header from File
|
* Extract header from File
|
||||||
*/
|
*/
|
||||||
public void extractTarHeader(String entryName) {
|
public void extractTarHeader(String entryName) {
|
||||||
int permissions = PermissionUtils.permissions(file);
|
int permissions = PermissionUtils.permissions(file);
|
||||||
header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory(), permissions);
|
header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory(), permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate checksum
|
* Calculate checksum
|
||||||
*/
|
*/
|
||||||
public long computeCheckSum(byte[] buf) {
|
public long computeCheckSum(byte[] buf) {
|
||||||
long sum = 0;
|
long sum = 0;
|
||||||
|
|
||||||
for (int i = 0; i < buf.length; ++i) {
|
for (int i = 0; i < buf.length; ++i) {
|
||||||
sum += 255 & buf[i];
|
sum += 255 & buf[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the header to the byte buffer
|
* Writes the header to the byte buffer
|
||||||
*/
|
*/
|
||||||
public void writeEntryHeader(byte[] outbuf) {
|
public void writeEntryHeader(byte[] outbuf) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
offset = TarHeader.getNameBytes(header.name, outbuf, offset, TarHeader.NAMELEN);
|
offset = TarHeader.getNameBytes(header.name, outbuf, offset, TarHeader.NAMELEN);
|
||||||
offset = Octal.getOctalBytes(header.mode, outbuf, offset, TarHeader.MODELEN);
|
offset = Octal.getOctalBytes(header.mode, outbuf, offset, TarHeader.MODELEN);
|
||||||
offset = Octal.getOctalBytes(header.userId, outbuf, offset, TarHeader.UIDLEN);
|
offset = Octal.getOctalBytes(header.userId, outbuf, offset, TarHeader.UIDLEN);
|
||||||
offset = Octal.getOctalBytes(header.groupId, outbuf, offset, TarHeader.GIDLEN);
|
offset = Octal.getOctalBytes(header.groupId, outbuf, offset, TarHeader.GIDLEN);
|
||||||
|
|
||||||
long size = header.size;
|
long size = header.size;
|
||||||
|
|
||||||
offset = Octal.getLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN);
|
offset = Octal.getLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN);
|
||||||
offset = Octal.getLongOctalBytes(header.modTime, outbuf, offset, TarHeader.MODTIMELEN);
|
offset = Octal.getLongOctalBytes(header.modTime, outbuf, offset, TarHeader.MODTIMELEN);
|
||||||
|
|
||||||
int csOffset = offset;
|
int csOffset = offset;
|
||||||
for (int c = 0; c < TarHeader.CHKSUMLEN; ++c)
|
for (int c = 0; c < TarHeader.CHKSUMLEN; ++c)
|
||||||
outbuf[offset++] = (byte) ' ';
|
outbuf[offset++] = (byte) ' ';
|
||||||
|
|
||||||
outbuf[offset++] = header.linkFlag;
|
outbuf[offset++] = header.linkFlag;
|
||||||
|
|
||||||
offset = TarHeader.getNameBytes(header.linkName, outbuf, offset, TarHeader.NAMELEN);
|
offset = TarHeader.getNameBytes(header.linkName, outbuf, offset, TarHeader.NAMELEN);
|
||||||
offset = TarHeader.getNameBytes(header.magic, outbuf, offset, TarHeader.USTAR_MAGICLEN);
|
offset = TarHeader.getNameBytes(header.magic, outbuf, offset, TarHeader.USTAR_MAGICLEN);
|
||||||
offset = TarHeader.getNameBytes(header.userName, outbuf, offset, TarHeader.USTAR_USER_NAMELEN);
|
offset = TarHeader.getNameBytes(header.userName, outbuf, offset, TarHeader.USTAR_USER_NAMELEN);
|
||||||
offset = TarHeader.getNameBytes(header.groupName, outbuf, offset, TarHeader.USTAR_GROUP_NAMELEN);
|
offset = TarHeader.getNameBytes(header.groupName, outbuf, offset, TarHeader.USTAR_GROUP_NAMELEN);
|
||||||
offset = Octal.getOctalBytes(header.devMajor, outbuf, offset, TarHeader.USTAR_DEVLEN);
|
offset = Octal.getOctalBytes(header.devMajor, outbuf, offset, TarHeader.USTAR_DEVLEN);
|
||||||
offset = Octal.getOctalBytes(header.devMinor, outbuf, offset, TarHeader.USTAR_DEVLEN);
|
offset = Octal.getOctalBytes(header.devMinor, outbuf, offset, TarHeader.USTAR_DEVLEN);
|
||||||
offset = TarHeader.getNameBytes(header.namePrefix, outbuf, offset, TarHeader.USTAR_FILENAME_PREFIX);
|
offset = TarHeader.getNameBytes(header.namePrefix, outbuf, offset, TarHeader.USTAR_FILENAME_PREFIX);
|
||||||
|
|
||||||
for (; offset < outbuf.length;)
|
for (; offset < outbuf.length;)
|
||||||
outbuf[offset++] = 0;
|
outbuf[offset++] = 0;
|
||||||
|
|
||||||
long checkSum = this.computeCheckSum(outbuf);
|
long checkSum = this.computeCheckSum(outbuf);
|
||||||
|
|
||||||
Octal.getCheckSumOctalBytes(checkSum, outbuf, csOffset, TarHeader.CHKSUMLEN);
|
Octal.getCheckSumOctalBytes(checkSum, outbuf, csOffset, TarHeader.CHKSUMLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the tar header to the byte buffer
|
* Parses the tar header to the byte buffer
|
||||||
*/
|
*/
|
||||||
public void parseTarHeader(byte[] bh) {
|
public void parseTarHeader(byte[] bh) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
header.name = TarHeader.parseName(bh, offset, TarHeader.NAMELEN);
|
header.name = TarHeader.parseName(bh, offset, TarHeader.NAMELEN);
|
||||||
offset += TarHeader.NAMELEN;
|
offset += TarHeader.NAMELEN;
|
||||||
|
|
||||||
header.mode = (int) Octal.parseOctal(bh, offset, TarHeader.MODELEN);
|
header.mode = (int) Octal.parseOctal(bh, offset, TarHeader.MODELEN);
|
||||||
offset += TarHeader.MODELEN;
|
offset += TarHeader.MODELEN;
|
||||||
|
|
||||||
header.userId = (int) Octal.parseOctal(bh, offset, TarHeader.UIDLEN);
|
header.userId = (int) Octal.parseOctal(bh, offset, TarHeader.UIDLEN);
|
||||||
offset += TarHeader.UIDLEN;
|
offset += TarHeader.UIDLEN;
|
||||||
|
|
||||||
header.groupId = (int) Octal.parseOctal(bh, offset, TarHeader.GIDLEN);
|
header.groupId = (int) Octal.parseOctal(bh, offset, TarHeader.GIDLEN);
|
||||||
offset += TarHeader.GIDLEN;
|
offset += TarHeader.GIDLEN;
|
||||||
|
|
||||||
header.size = Octal.parseOctal(bh, offset, TarHeader.SIZELEN);
|
header.size = Octal.parseOctal(bh, offset, TarHeader.SIZELEN);
|
||||||
offset += TarHeader.SIZELEN;
|
offset += TarHeader.SIZELEN;
|
||||||
|
|
||||||
header.modTime = Octal.parseOctal(bh, offset, TarHeader.MODTIMELEN);
|
header.modTime = Octal.parseOctal(bh, offset, TarHeader.MODTIMELEN);
|
||||||
offset += TarHeader.MODTIMELEN;
|
offset += TarHeader.MODTIMELEN;
|
||||||
|
|
||||||
header.checkSum = (int) Octal.parseOctal(bh, offset, TarHeader.CHKSUMLEN);
|
header.checkSum = (int) Octal.parseOctal(bh, offset, TarHeader.CHKSUMLEN);
|
||||||
offset += TarHeader.CHKSUMLEN;
|
offset += TarHeader.CHKSUMLEN;
|
||||||
|
|
||||||
header.linkFlag = bh[offset++];
|
header.linkFlag = bh[offset++];
|
||||||
|
|
||||||
header.linkName = TarHeader.parseName(bh, offset, TarHeader.NAMELEN);
|
header.linkName = TarHeader.parseName(bh, offset, TarHeader.NAMELEN);
|
||||||
offset += TarHeader.NAMELEN;
|
offset += TarHeader.NAMELEN;
|
||||||
|
|
||||||
header.magic = TarHeader.parseName(bh, offset, TarHeader.USTAR_MAGICLEN);
|
header.magic = TarHeader.parseName(bh, offset, TarHeader.USTAR_MAGICLEN);
|
||||||
offset += TarHeader.USTAR_MAGICLEN;
|
offset += TarHeader.USTAR_MAGICLEN;
|
||||||
|
|
||||||
header.userName = TarHeader.parseName(bh, offset, TarHeader.USTAR_USER_NAMELEN);
|
header.userName = TarHeader.parseName(bh, offset, TarHeader.USTAR_USER_NAMELEN);
|
||||||
offset += TarHeader.USTAR_USER_NAMELEN;
|
offset += TarHeader.USTAR_USER_NAMELEN;
|
||||||
|
|
||||||
header.groupName = TarHeader.parseName(bh, offset, TarHeader.USTAR_GROUP_NAMELEN);
|
header.groupName = TarHeader.parseName(bh, offset, TarHeader.USTAR_GROUP_NAMELEN);
|
||||||
offset += TarHeader.USTAR_GROUP_NAMELEN;
|
offset += TarHeader.USTAR_GROUP_NAMELEN;
|
||||||
|
|
||||||
header.devMajor = (int) Octal.parseOctal(bh, offset, TarHeader.USTAR_DEVLEN);
|
header.devMajor = (int) Octal.parseOctal(bh, offset, TarHeader.USTAR_DEVLEN);
|
||||||
offset += TarHeader.USTAR_DEVLEN;
|
offset += TarHeader.USTAR_DEVLEN;
|
||||||
|
|
||||||
header.devMinor = (int) Octal.parseOctal(bh, offset, TarHeader.USTAR_DEVLEN);
|
header.devMinor = (int) Octal.parseOctal(bh, offset, TarHeader.USTAR_DEVLEN);
|
||||||
offset += TarHeader.USTAR_DEVLEN;
|
offset += TarHeader.USTAR_DEVLEN;
|
||||||
|
|
||||||
header.namePrefix = TarHeader.parseName(bh, offset, TarHeader.USTAR_FILENAME_PREFIX);
|
header.namePrefix = TarHeader.parseName(bh, offset, TarHeader.USTAR_FILENAME_PREFIX);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -69,169 +69,169 @@ import java.io.File;
|
|||||||
|
|
||||||
public class TarHeader {
|
public class TarHeader {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Header
|
* Header
|
||||||
*/
|
*/
|
||||||
public static final int NAMELEN = 100;
|
public static final int NAMELEN = 100;
|
||||||
public static final int MODELEN = 8;
|
public static final int MODELEN = 8;
|
||||||
public static final int UIDLEN = 8;
|
public static final int UIDLEN = 8;
|
||||||
public static final int GIDLEN = 8;
|
public static final int GIDLEN = 8;
|
||||||
public static final int SIZELEN = 12;
|
public static final int SIZELEN = 12;
|
||||||
public static final int MODTIMELEN = 12;
|
public static final int MODTIMELEN = 12;
|
||||||
public static final int CHKSUMLEN = 8;
|
public static final int CHKSUMLEN = 8;
|
||||||
public static final byte LF_OLDNORM = 0;
|
public static final byte LF_OLDNORM = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File Types
|
* File Types
|
||||||
*/
|
*/
|
||||||
public static final byte LF_NORMAL = (byte) '0';
|
public static final byte LF_NORMAL = (byte) '0';
|
||||||
public static final byte LF_LINK = (byte) '1';
|
public static final byte LF_LINK = (byte) '1';
|
||||||
public static final byte LF_SYMLINK = (byte) '2';
|
public static final byte LF_SYMLINK = (byte) '2';
|
||||||
public static final byte LF_CHR = (byte) '3';
|
public static final byte LF_CHR = (byte) '3';
|
||||||
public static final byte LF_BLK = (byte) '4';
|
public static final byte LF_BLK = (byte) '4';
|
||||||
public static final byte LF_DIR = (byte) '5';
|
public static final byte LF_DIR = (byte) '5';
|
||||||
public static final byte LF_FIFO = (byte) '6';
|
public static final byte LF_FIFO = (byte) '6';
|
||||||
public static final byte LF_CONTIG = (byte) '7';
|
public static final byte LF_CONTIG = (byte) '7';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ustar header
|
* Ustar header
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static final String USTAR_MAGIC = "ustar"; // POSIX
|
public static final String USTAR_MAGIC = "ustar"; // POSIX
|
||||||
|
|
||||||
public static final int USTAR_MAGICLEN = 8;
|
public static final int USTAR_MAGICLEN = 8;
|
||||||
public static final int USTAR_USER_NAMELEN = 32;
|
public static final int USTAR_USER_NAMELEN = 32;
|
||||||
public static final int USTAR_GROUP_NAMELEN = 32;
|
public static final int USTAR_GROUP_NAMELEN = 32;
|
||||||
public static final int USTAR_DEVLEN = 8;
|
public static final int USTAR_DEVLEN = 8;
|
||||||
public static final int USTAR_FILENAME_PREFIX = 155;
|
public static final int USTAR_FILENAME_PREFIX = 155;
|
||||||
|
|
||||||
// Header values
|
// Header values
|
||||||
public StringBuffer name;
|
public StringBuffer name;
|
||||||
public int mode;
|
public int mode;
|
||||||
public int userId;
|
public int userId;
|
||||||
public int groupId;
|
public int groupId;
|
||||||
public long size;
|
public long size;
|
||||||
public long modTime;
|
public long modTime;
|
||||||
public int checkSum;
|
public int checkSum;
|
||||||
public byte linkFlag;
|
public byte linkFlag;
|
||||||
public StringBuffer linkName;
|
public StringBuffer linkName;
|
||||||
public StringBuffer magic; // ustar indicator and version
|
public StringBuffer magic; // ustar indicator and version
|
||||||
public StringBuffer userName;
|
public StringBuffer userName;
|
||||||
public StringBuffer groupName;
|
public StringBuffer groupName;
|
||||||
public int devMajor;
|
public int devMajor;
|
||||||
public int devMinor;
|
public int devMinor;
|
||||||
public StringBuffer namePrefix;
|
public StringBuffer namePrefix;
|
||||||
|
|
||||||
public TarHeader() {
|
public TarHeader() {
|
||||||
this.magic = new StringBuffer(TarHeader.USTAR_MAGIC);
|
this.magic = new StringBuffer(TarHeader.USTAR_MAGIC);
|
||||||
|
|
||||||
this.name = new StringBuffer();
|
this.name = new StringBuffer();
|
||||||
this.linkName = new StringBuffer();
|
this.linkName = new StringBuffer();
|
||||||
|
|
||||||
String user = System.getProperty("user.name", "");
|
String user = System.getProperty("user.name", "");
|
||||||
|
|
||||||
if (user.length() > 31)
|
if (user.length() > 31)
|
||||||
user = user.substring(0, 31);
|
user = user.substring(0, 31);
|
||||||
|
|
||||||
this.userId = 0;
|
this.userId = 0;
|
||||||
this.groupId = 0;
|
this.groupId = 0;
|
||||||
this.userName = new StringBuffer(user);
|
this.userName = new StringBuffer(user);
|
||||||
this.groupName = new StringBuffer("");
|
this.groupName = new StringBuffer("");
|
||||||
this.namePrefix = new StringBuffer();
|
this.namePrefix = new StringBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an entry name from a header buffer.
|
* Parse an entry name from a header buffer.
|
||||||
*
|
*
|
||||||
* @param header
|
* @param header
|
||||||
* The header buffer from which to parse.
|
* The header buffer from which to parse.
|
||||||
* @param offset
|
* @param offset
|
||||||
* The offset into the buffer from which to parse.
|
* The offset into the buffer from which to parse.
|
||||||
* @param length
|
* @param length
|
||||||
* The number of header bytes to parse.
|
* The number of header bytes to parse.
|
||||||
* @return The header's entry name.
|
* @return The header's entry name.
|
||||||
*/
|
*/
|
||||||
public static StringBuffer parseName(byte[] header, int offset, int length) {
|
public static StringBuffer parseName(byte[] header, int offset, int length) {
|
||||||
StringBuffer result = new StringBuffer(length);
|
StringBuffer result = new StringBuffer(length);
|
||||||
|
|
||||||
int end = offset + length;
|
int end = offset + length;
|
||||||
for (int i = offset; i < end; ++i) {
|
for (int i = offset; i < end; ++i) {
|
||||||
if (header[i] == 0)
|
if (header[i] == 0)
|
||||||
break;
|
break;
|
||||||
result.append((char) header[i]);
|
result.append((char) header[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the number of bytes in an entry name.
|
* Determine the number of bytes in an entry name.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The header buffer from which to parse.
|
* The header buffer from which to parse.
|
||||||
* @param offset
|
* @param offset
|
||||||
* The offset into the buffer from which to parse.
|
* The offset into the buffer from which to parse.
|
||||||
* @param length
|
* @param length
|
||||||
* The number of header bytes to parse.
|
* The number of header bytes to parse.
|
||||||
* @return The number of bytes in a header's entry name.
|
* @return The number of bytes in a header's entry name.
|
||||||
*/
|
*/
|
||||||
public static int getNameBytes(StringBuffer name, byte[] buf, int offset, int length) {
|
public static int getNameBytes(StringBuffer name, byte[] buf, int offset, int length) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < length && i < name.length(); ++i) {
|
for (i = 0; i < length && i < name.length(); ++i) {
|
||||||
buf[offset + i] = (byte) name.charAt(i);
|
buf[offset + i] = (byte) name.charAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; i < length; ++i) {
|
for (; i < length; ++i) {
|
||||||
buf[offset + i] = 0;
|
buf[offset + i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset + length;
|
return offset + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new header for a file/directory entry.
|
* Creates a new header for a file/directory entry.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param entryName
|
* @param entryName
|
||||||
* File name
|
* File name
|
||||||
* @param size
|
* @param size
|
||||||
* File size in bytes
|
* File size in bytes
|
||||||
* @param modTime
|
* @param modTime
|
||||||
* Last modification time in numeric Unix time format
|
* Last modification time in numeric Unix time format
|
||||||
* @param dir
|
* @param dir
|
||||||
* Is directory
|
* Is directory
|
||||||
*/
|
*/
|
||||||
public static TarHeader createHeader(String entryName, long size, long modTime, boolean dir, int permissions) {
|
public static TarHeader createHeader(String entryName, long size, long modTime, boolean dir, int permissions) {
|
||||||
String name = entryName;
|
String name = entryName;
|
||||||
name = TarUtils.trim(name.replace(File.separatorChar, '/'), '/');
|
name = TarUtils.trim(name.replace(File.separatorChar, '/'), '/');
|
||||||
|
|
||||||
TarHeader header = new TarHeader();
|
TarHeader header = new TarHeader();
|
||||||
header.linkName = new StringBuffer("");
|
header.linkName = new StringBuffer("");
|
||||||
header.mode = permissions;
|
header.mode = permissions;
|
||||||
|
|
||||||
if (name.length() > 100) {
|
if (name.length() > 100) {
|
||||||
header.namePrefix = new StringBuffer(name.substring(0, name.lastIndexOf('/')));
|
header.namePrefix = new StringBuffer(name.substring(0, name.lastIndexOf('/')));
|
||||||
header.name = new StringBuffer(name.substring(name.lastIndexOf('/') + 1));
|
header.name = new StringBuffer(name.substring(name.lastIndexOf('/') + 1));
|
||||||
} else {
|
} else {
|
||||||
header.name = new StringBuffer(name);
|
header.name = new StringBuffer(name);
|
||||||
}
|
}
|
||||||
if (dir) {
|
if (dir) {
|
||||||
header.linkFlag = TarHeader.LF_DIR;
|
header.linkFlag = TarHeader.LF_DIR;
|
||||||
if (header.name.charAt(header.name.length() - 1) != '/') {
|
if (header.name.charAt(header.name.length() - 1) != '/') {
|
||||||
header.name.append("/");
|
header.name.append("/");
|
||||||
}
|
}
|
||||||
header.size = 0;
|
header.size = 0;
|
||||||
} else {
|
} else {
|
||||||
header.linkFlag = TarHeader.LF_NORMAL;
|
header.linkFlag = TarHeader.LF_NORMAL;
|
||||||
header.size = size;
|
header.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
header.modTime = modTime;
|
header.modTime = modTime;
|
||||||
header.checkSum = 0;
|
header.checkSum = 0;
|
||||||
header.devMajor = 0;
|
header.devMajor = 0;
|
||||||
header.devMinor = 0;
|
header.devMinor = 0;
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,223 +27,223 @@ import java.io.InputStream;
|
|||||||
*/
|
*/
|
||||||
public class TarInputStream extends FilterInputStream {
|
public class TarInputStream extends FilterInputStream {
|
||||||
|
|
||||||
private static final int SKIP_BUFFER_SIZE = 2048;
|
private static final int SKIP_BUFFER_SIZE = 2048;
|
||||||
private TarEntry currentEntry;
|
private TarEntry currentEntry;
|
||||||
private long currentFileSize;
|
private long currentFileSize;
|
||||||
private long bytesRead;
|
private long bytesRead;
|
||||||
private boolean defaultSkip = false;
|
private boolean defaultSkip = false;
|
||||||
|
|
||||||
public TarInputStream(InputStream in) {
|
public TarInputStream(InputStream in) {
|
||||||
super(in);
|
super(in);
|
||||||
currentFileSize = 0;
|
currentFileSize = 0;
|
||||||
bytesRead = 0;
|
bytesRead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean markSupported() {
|
public boolean markSupported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not supported
|
* Not supported
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void mark(int readlimit) {
|
public synchronized void mark(int readlimit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not supported
|
* Not supported
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void reset() throws IOException {
|
public synchronized void reset() throws IOException {
|
||||||
throw new IOException("mark/reset not supported");
|
throw new IOException("mark/reset not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a byte
|
* Read a byte
|
||||||
*
|
*
|
||||||
* @see java.io.FilterInputStream#read()
|
* @see java.io.FilterInputStream#read()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
byte[] buf = new byte[1];
|
byte[] buf = new byte[1];
|
||||||
|
|
||||||
int res = this.read(buf, 0, 1);
|
int res = this.read(buf, 0, 1);
|
||||||
|
|
||||||
if (res != -1) {
|
if (res != -1) {
|
||||||
return 0xFF & buf[0];
|
return 0xFF & buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the bytes being read exceed the entry size and adjusts the byte
|
* Checks if the bytes being read exceed the entry size and adjusts the byte
|
||||||
* array length. Updates the byte counters
|
* array length. Updates the byte counters
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @see java.io.FilterInputStream#read(byte[], int, int)
|
* @see java.io.FilterInputStream#read(byte[], int, int)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] b, int off, int len) throws IOException {
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
if (currentEntry != null) {
|
if (currentEntry != null) {
|
||||||
if (currentFileSize == currentEntry.getSize()) {
|
if (currentFileSize == currentEntry.getSize()) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if ((currentEntry.getSize() - currentFileSize) < len) {
|
} else if ((currentEntry.getSize() - currentFileSize) < len) {
|
||||||
len = (int) (currentEntry.getSize() - currentFileSize);
|
len = (int) (currentEntry.getSize() - currentFileSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int br = super.read(b, off, len);
|
int br = super.read(b, off, len);
|
||||||
|
|
||||||
if (br != -1) {
|
if (br != -1) {
|
||||||
if (currentEntry != null) {
|
if (currentEntry != null) {
|
||||||
currentFileSize += br;
|
currentFileSize += br;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesRead += br;
|
bytesRead += br;
|
||||||
}
|
}
|
||||||
|
|
||||||
return br;
|
return br;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next entry in the tar file
|
* Returns the next entry in the tar file
|
||||||
*
|
*
|
||||||
* @return TarEntry
|
* @return TarEntry
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public TarEntry getNextEntry() throws IOException {
|
public TarEntry getNextEntry() throws IOException {
|
||||||
closeCurrentEntry();
|
closeCurrentEntry();
|
||||||
|
|
||||||
byte[] header = new byte[TarConstants.HEADER_BLOCK];
|
byte[] header = new byte[TarConstants.HEADER_BLOCK];
|
||||||
byte[] theader = new byte[TarConstants.HEADER_BLOCK];
|
byte[] theader = new byte[TarConstants.HEADER_BLOCK];
|
||||||
int tr = 0;
|
int tr = 0;
|
||||||
|
|
||||||
// Read full header
|
// Read full header
|
||||||
while (tr < TarConstants.HEADER_BLOCK) {
|
while (tr < TarConstants.HEADER_BLOCK) {
|
||||||
int res = read(theader, 0, TarConstants.HEADER_BLOCK - tr);
|
int res = read(theader, 0, TarConstants.HEADER_BLOCK - tr);
|
||||||
|
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.arraycopy(theader, 0, header, tr, res);
|
System.arraycopy(theader, 0, header, tr, res);
|
||||||
tr += res;
|
tr += res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if record is null
|
// Check if record is null
|
||||||
boolean eof = true;
|
boolean eof = true;
|
||||||
for (byte b : header) {
|
for (byte b : header) {
|
||||||
if (b != 0) {
|
if (b != 0) {
|
||||||
eof = false;
|
eof = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eof) {
|
if (!eof) {
|
||||||
currentEntry = new TarEntry(header);
|
currentEntry = new TarEntry(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentEntry;
|
return currentEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current offset (in bytes) from the beginning of the stream.
|
* Returns the current offset (in bytes) from the beginning of the stream.
|
||||||
* This can be used to find out at which point in a tar file an entry's content begins, for instance.
|
* This can be used to find out at which point in a tar file an entry's content begins, for instance.
|
||||||
*/
|
*/
|
||||||
public long getCurrentOffset() {
|
public long getCurrentOffset() {
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the current tar entry
|
* Closes the current tar entry
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected void closeCurrentEntry() throws IOException {
|
protected void closeCurrentEntry() throws IOException {
|
||||||
if (currentEntry != null) {
|
if (currentEntry != null) {
|
||||||
if (currentEntry.getSize() > currentFileSize) {
|
if (currentEntry.getSize() > currentFileSize) {
|
||||||
// Not fully read, skip rest of the bytes
|
// Not fully read, skip rest of the bytes
|
||||||
long bs = 0;
|
long bs = 0;
|
||||||
while (bs < currentEntry.getSize() - currentFileSize) {
|
while (bs < currentEntry.getSize() - currentFileSize) {
|
||||||
long res = skip(currentEntry.getSize() - currentFileSize - bs);
|
long res = skip(currentEntry.getSize() - currentFileSize - bs);
|
||||||
|
|
||||||
if (res == 0 && currentEntry.getSize() - currentFileSize > 0) {
|
if (res == 0 && currentEntry.getSize() - currentFileSize > 0) {
|
||||||
// I suspect file corruption
|
// I suspect file corruption
|
||||||
throw new IOException("Possible tar file corruption");
|
throw new IOException("Possible tar file corruption");
|
||||||
}
|
}
|
||||||
|
|
||||||
bs += res;
|
bs += res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentEntry = null;
|
currentEntry = null;
|
||||||
currentFileSize = 0L;
|
currentFileSize = 0L;
|
||||||
skipPad();
|
skipPad();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skips the pad at the end of each tar entry file content
|
* Skips the pad at the end of each tar entry file content
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected void skipPad() throws IOException {
|
protected void skipPad() throws IOException {
|
||||||
if (bytesRead > 0) {
|
if (bytesRead > 0) {
|
||||||
int extra = (int) (bytesRead % TarConstants.DATA_BLOCK);
|
int extra = (int) (bytesRead % TarConstants.DATA_BLOCK);
|
||||||
|
|
||||||
if (extra > 0) {
|
if (extra > 0) {
|
||||||
long bs = 0;
|
long bs = 0;
|
||||||
while (bs < TarConstants.DATA_BLOCK - extra) {
|
while (bs < TarConstants.DATA_BLOCK - extra) {
|
||||||
long res = skip(TarConstants.DATA_BLOCK - extra - bs);
|
long res = skip(TarConstants.DATA_BLOCK - extra - bs);
|
||||||
bs += res;
|
bs += res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skips 'n' bytes on the InputStream<br>
|
* Skips 'n' bytes on the InputStream<br>
|
||||||
* Overrides default implementation of skip
|
* Overrides default implementation of skip
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long skip(long n) throws IOException {
|
public long skip(long n) throws IOException {
|
||||||
if (defaultSkip) {
|
if (defaultSkip) {
|
||||||
// use skip method of parent stream
|
// use skip method of parent stream
|
||||||
// may not work if skip not implemented by parent
|
// may not work if skip not implemented by parent
|
||||||
long bs = super.skip(n);
|
long bs = super.skip(n);
|
||||||
bytesRead += bs;
|
bytesRead += bs;
|
||||||
|
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long left = n;
|
long left = n;
|
||||||
byte[] sBuff = new byte[SKIP_BUFFER_SIZE];
|
byte[] sBuff = new byte[SKIP_BUFFER_SIZE];
|
||||||
|
|
||||||
while (left > 0) {
|
while (left > 0) {
|
||||||
int res = read(sBuff, 0, (int) (left < SKIP_BUFFER_SIZE ? left : SKIP_BUFFER_SIZE));
|
int res = read(sBuff, 0, (int) (left < SKIP_BUFFER_SIZE ? left : SKIP_BUFFER_SIZE));
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
left -= res;
|
left -= res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return n - left;
|
return n - left;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDefaultSkip() {
|
public boolean isDefaultSkip() {
|
||||||
return defaultSkip;
|
return defaultSkip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultSkip(boolean defaultSkip) {
|
public void setDefaultSkip(boolean defaultSkip) {
|
||||||
this.defaultSkip = defaultSkip;
|
this.defaultSkip = defaultSkip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,20 +17,14 @@
|
|||||||
|
|
||||||
package org.kamranzafar.jtar;
|
package org.kamranzafar.jtar;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.*;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kamran Zafar
|
* @author Kamran Zafar
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TarOutputStream extends OutputStream {
|
public class TarOutputStream extends OutputStream {
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
private long bytesWritten;
|
private long bytesWritten;
|
||||||
private long currentFileSize;
|
private long currentFileSize;
|
||||||
private TarEntry currentEntry;
|
private TarEntry currentEntry;
|
||||||
@ -41,24 +35,24 @@ public class TarOutputStream extends OutputStream {
|
|||||||
currentFileSize = 0;
|
currentFileSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TarOutputStream(final File fout) throws FileNotFoundException {
|
public TarOutputStream(final File fout) throws FileNotFoundException {
|
||||||
this.out = new BufferedOutputStream(new FileOutputStream(fout));
|
this.out = new BufferedOutputStream(new FileOutputStream(fout));
|
||||||
bytesWritten = 0;
|
bytesWritten = 0;
|
||||||
currentFileSize = 0;
|
currentFileSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a file for writing.
|
* Opens a file for writing.
|
||||||
*/
|
*/
|
||||||
public TarOutputStream(final File fout, final boolean append) throws IOException {
|
public TarOutputStream(final File fout, final boolean append) throws IOException {
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
RandomAccessFile raf = new RandomAccessFile(fout, "rw");
|
RandomAccessFile raf = new RandomAccessFile(fout, "rw");
|
||||||
final long fileSize = fout.length();
|
final long fileSize = fout.length();
|
||||||
if (append && fileSize > TarConstants.EOF_BLOCK) {
|
if (append && fileSize > TarConstants.EOF_BLOCK) {
|
||||||
raf.seek(fileSize - TarConstants.EOF_BLOCK);
|
raf.seek(fileSize - TarConstants.EOF_BLOCK);
|
||||||
}
|
}
|
||||||
out = new BufferedOutputStream(new FileOutputStream(raf.getFD()));
|
out = new BufferedOutputStream(new FileOutputStream(raf.getFD()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends the EOF record and closes the stream
|
* Appends the EOF record and closes the stream
|
||||||
|
@ -24,70 +24,70 @@ import java.io.File;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TarUtils {
|
public class TarUtils {
|
||||||
/**
|
/**
|
||||||
* Determines the tar file size of the given folder/file path
|
* Determines the tar file size of the given folder/file path
|
||||||
*/
|
*/
|
||||||
public static long calculateTarSize(File path) {
|
public static long calculateTarSize(File path) {
|
||||||
return tarSize(path) + TarConstants.EOF_BLOCK;
|
return tarSize(path) + TarConstants.EOF_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long tarSize(File dir) {
|
private static long tarSize(File dir) {
|
||||||
long size = 0;
|
long size = 0;
|
||||||
|
|
||||||
if (dir.isFile()) {
|
if (dir.isFile()) {
|
||||||
return entrySize(dir.length());
|
return entrySize(dir.length());
|
||||||
} else {
|
} else {
|
||||||
File[] subFiles = dir.listFiles();
|
File[] subFiles = dir.listFiles();
|
||||||
|
|
||||||
if (subFiles != null && subFiles.length > 0) {
|
if (subFiles != null && subFiles.length > 0) {
|
||||||
for (File file : subFiles) {
|
for (File file : subFiles) {
|
||||||
if (file.isFile()) {
|
if (file.isFile()) {
|
||||||
size += entrySize(file.length());
|
size += entrySize(file.length());
|
||||||
} else {
|
} else {
|
||||||
size += tarSize(file);
|
size += tarSize(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Empty folder header
|
// Empty folder header
|
||||||
return TarConstants.HEADER_BLOCK;
|
return TarConstants.HEADER_BLOCK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long entrySize(long fileSize) {
|
private static long entrySize(long fileSize) {
|
||||||
long size = 0;
|
long size = 0;
|
||||||
size += TarConstants.HEADER_BLOCK; // Header
|
size += TarConstants.HEADER_BLOCK; // Header
|
||||||
size += fileSize; // File size
|
size += fileSize; // File size
|
||||||
|
|
||||||
long extra = size % TarConstants.DATA_BLOCK;
|
long extra = size % TarConstants.DATA_BLOCK;
|
||||||
|
|
||||||
if (extra > 0) {
|
if (extra > 0) {
|
||||||
size += (TarConstants.DATA_BLOCK - extra); // pad
|
size += (TarConstants.DATA_BLOCK - extra); // pad
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String trim(String s, char c) {
|
public static String trim(String s, char c) {
|
||||||
StringBuffer tmp = new StringBuffer(s);
|
StringBuffer tmp = new StringBuffer(s);
|
||||||
for (int i = 0; i < tmp.length(); i++) {
|
for (int i = 0; i < tmp.length(); i++) {
|
||||||
if (tmp.charAt(i) != c) {
|
if (tmp.charAt(i) != c) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
tmp.deleteCharAt(i);
|
tmp.deleteCharAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = tmp.length() - 1; i >= 0; i--) {
|
for (int i = tmp.length() - 1; i >= 0; i--) {
|
||||||
if (tmp.charAt(i) != c) {
|
if (tmp.charAt(i) != c) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
tmp.deleteCharAt(i);
|
tmp.deleteCharAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp.toString();
|
return tmp.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user