mirror of
https://github.com/topjohnwu/jtar.git
synced 2024-11-23 11:29:47 +00:00
Merge pull request #20 from zamblauskas/preserve_file_permissions
Read and preserve actual file permissions mode in `TarHeader`.
This commit is contained in:
commit
70d0b56fce
109
src/main/java/org/kamranzafar/jtar/PermissionUtils.java
Normal file
109
src/main/java/org/kamranzafar/jtar/PermissionUtils.java
Normal file
@ -0,0 +1,109 @@
|
||||
package org.kamranzafar.jtar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helps dealing with file permissions.
|
||||
*/
|
||||
public class PermissionUtils {
|
||||
|
||||
/**
|
||||
* XXX: When using standard Java permissions, we treat 'owner' and 'group' equally and give no
|
||||
* permissions for 'others'.
|
||||
*/
|
||||
private static enum StandardFilePermission {
|
||||
EXECUTE(0110), WRITE(0220), READ(0440);
|
||||
|
||||
private int mode;
|
||||
|
||||
private StandardFilePermission(int mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<PosixFilePermission, Integer> posixPermissionToInteger = new HashMap<>();
|
||||
|
||||
static {
|
||||
posixPermissionToInteger.put(PosixFilePermission.OWNER_EXECUTE, 0100);
|
||||
posixPermissionToInteger.put(PosixFilePermission.OWNER_WRITE, 0200);
|
||||
posixPermissionToInteger.put(PosixFilePermission.OWNER_READ, 0400);
|
||||
|
||||
posixPermissionToInteger.put(PosixFilePermission.GROUP_EXECUTE, 0010);
|
||||
posixPermissionToInteger.put(PosixFilePermission.GROUP_WRITE, 0020);
|
||||
posixPermissionToInteger.put(PosixFilePermission.GROUP_READ, 0040);
|
||||
|
||||
posixPermissionToInteger.put(PosixFilePermission.OTHERS_EXECUTE, 0001);
|
||||
posixPermissionToInteger.put(PosixFilePermission.OTHERS_WRITE, 0002);
|
||||
posixPermissionToInteger.put(PosixFilePermission.OTHERS_READ, 0004);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file permissions in octal mode, e.g. 0755.
|
||||
*
|
||||
* 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
|
||||
* 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`.
|
||||
*
|
||||
* @throws NullPointerException if file is null.
|
||||
* @throws IllegalArgumentException if file does not exist.
|
||||
*/
|
||||
public static int permissions(File f) {
|
||||
if(f == null) {
|
||||
throw new NullPointerException("File is null.");
|
||||
}
|
||||
if(!f.exists()) {
|
||||
throw new IllegalArgumentException("File " + f + " does not exist.");
|
||||
}
|
||||
|
||||
return isPosix ? posixPermissions(f) : standardPermissions(f);
|
||||
}
|
||||
|
||||
private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
||||
|
||||
private static int posixPermissions(File f) {
|
||||
int number = 0;
|
||||
try {
|
||||
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(f.toPath());
|
||||
for (Map.Entry<PosixFilePermission, Integer> entry : posixPermissionToInteger.entrySet()) {
|
||||
if (permissions.contains(entry.getKey())) {
|
||||
number += entry.getValue();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
private static Set<StandardFilePermission> readStandardPermissions(File f) {
|
||||
Set<StandardFilePermission> permissions = new HashSet<>();
|
||||
if(f.canExecute()) {
|
||||
permissions.add(StandardFilePermission.EXECUTE);
|
||||
}
|
||||
if(f.canWrite()) {
|
||||
permissions.add(StandardFilePermission.WRITE);
|
||||
}
|
||||
if(f.canRead()) {
|
||||
permissions.add(StandardFilePermission.READ);
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
private static Integer standardPermissions(File f) {
|
||||
int number = 0;
|
||||
Set<StandardFilePermission> permissions = readStandardPermissions(f);
|
||||
for (StandardFilePermission permission : permissions) {
|
||||
number += permission.mode;
|
||||
}
|
||||
return number;
|
||||
}
|
||||
}
|
@ -170,7 +170,8 @@ public class TarEntry {
|
||||
* @param entryName
|
||||
*/
|
||||
public void extractTarHeader(String entryName) {
|
||||
header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory());
|
||||
int permissions = PermissionUtils.permissions(file);
|
||||
header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory(), permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,12 +206,13 @@ public class TarHeader {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static TarHeader createHeader(String entryName, long size, long modTime, boolean dir) {
|
||||
public static TarHeader createHeader(String entryName, long size, long modTime, boolean dir, int permissions) {
|
||||
String name = entryName;
|
||||
name = TarUtils.trim(name.replace(File.separatorChar, '/'), '/');
|
||||
|
||||
TarHeader header = new TarHeader();
|
||||
header.linkName = new StringBuffer("");
|
||||
header.mode = permissions;
|
||||
|
||||
if (name.length() > 100) {
|
||||
header.namePrefix = new StringBuffer(name.substring(0, name.lastIndexOf('/')));
|
||||
@ -219,16 +220,13 @@ public class TarHeader {
|
||||
} else {
|
||||
header.name = new StringBuffer(name);
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
header.mode = 040755;
|
||||
header.linkFlag = TarHeader.LF_DIR;
|
||||
if (header.name.charAt(header.name.length() - 1) != '/') {
|
||||
header.name.append("/");
|
||||
}
|
||||
header.size = 0;
|
||||
} else {
|
||||
header.mode = 0100644;
|
||||
header.linkFlag = TarHeader.LF_NORMAL;
|
||||
header.size = size;
|
||||
}
|
||||
|
@ -245,13 +245,15 @@ public class JTarTest {
|
||||
String fileName = "file.txt";
|
||||
long fileSize = 14523;
|
||||
long modTime = System.currentTimeMillis() / 1000;
|
||||
int permissions = 0755;
|
||||
|
||||
// Create a header object and check the fields
|
||||
TarHeader fileHeader = TarHeader.createHeader(fileName, fileSize, modTime, false);
|
||||
TarHeader fileHeader = TarHeader.createHeader(fileName, fileSize, modTime, false, permissions);
|
||||
assertEquals(fileName, fileHeader.name.toString());
|
||||
assertEquals(TarHeader.LF_NORMAL, fileHeader.linkFlag);
|
||||
assertEquals(fileSize, fileHeader.size);
|
||||
assertEquals(modTime, fileHeader.modTime);
|
||||
assertEquals(permissions, fileHeader.mode);
|
||||
|
||||
// Create an entry from the header
|
||||
TarEntry fileEntry = new TarEntry(fileHeader);
|
||||
|
Loading…
Reference in New Issue
Block a user