Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use NIO to set file permissions #557

Merged
merged 5 commits into from Jun 17, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -16,14 +16,26 @@

import com.google.api.client.util.IOUtils;
import com.google.api.client.util.Maps;
import com.google.api.client.util.Throwables;

import com.google.common.base.StandardSystemProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclEntryPermission;
import java.nio.file.attribute.AclEntryType;
import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipal;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

/**
Expand All @@ -40,6 +52,9 @@ public class FileDataStoreFactory extends AbstractDataStoreFactory {

private static final Logger LOGGER = Logger.getLogger(FileDataStoreFactory.class.getName());

private static final boolean IS_WINDOWS = StandardSystemProperty.OS_NAME.value()
.startsWith("WINDOWS");

/** Directory to store data. */
private final File dataDirectory;

Expand All @@ -55,7 +70,12 @@ public FileDataStoreFactory(File dataDirectory) throws IOException {
if (!dataDirectory.exists() && !dataDirectory.mkdirs()) {
throw new IOException("unable to create directory: " + dataDirectory);
}
setPermissionsToOwnerOnly(dataDirectory);

if (IS_WINDOWS) {
setPermissionsToOwnerOnlyWindows(dataDirectory);
} else {
setPermissionsToOwnerOnly(dataDirectory);
}
}

/** Returns the data directory. */
Expand Down Expand Up @@ -117,38 +137,55 @@ public FileDataStoreFactory getDataStoreFactory() {
* @throws IOException
*/
static void setPermissionsToOwnerOnly(File file) throws IOException {
// Disable access by other users if O/S allows it and set file permissions to readable and
// writable by user. Use reflection since JDK 1.5 will not have these methods
Set permissions = new HashSet<PosixFilePermission>();
permissions.add(PosixFilePermission.OWNER_READ);
permissions.add(PosixFilePermission.OWNER_WRITE);
permissions.add(PosixFilePermission.OWNER_EXECUTE);
try {
Method setReadable = File.class.getMethod("setReadable", boolean.class, boolean.class);
Method setWritable = File.class.getMethod("setWritable", boolean.class, boolean.class);
Method setExecutable = File.class.getMethod("setExecutable", boolean.class, boolean.class);
if (!(Boolean) setReadable.invoke(file, false, false)
|| !(Boolean) setWritable.invoke(file, false, false)
|| !(Boolean) setExecutable.invoke(file, false, false)) {
LOGGER.warning("unable to change permissions for everybody: " + file);
}
if (!(Boolean) setReadable.invoke(file, true, true)
|| !(Boolean) setWritable.invoke(file, true, true)
|| !(Boolean) setExecutable.invoke(file, true, true)) {
LOGGER.warning("unable to change permissions for owner: " + file);
}
} catch (InvocationTargetException exception) {
Throwable cause = exception.getCause();
Throwables.propagateIfPossible(cause, IOException.class);
// shouldn't reach this point, but just in case...
throw new RuntimeException(cause);
} catch (NoSuchMethodException exception) {
LOGGER.warning(
"Unable to set permissions for "
+ file
+ ", likely because you are running a version of Java prior to 1.6");
Files.setPosixFilePermissions(Paths.get(file.getAbsolutePath()), permissions);
} catch (UnsupportedOperationException exception) {
LOGGER.warning("Unable to set permissions for " + file
+ ", because you are running on a non-POSIX file system.");
} catch (SecurityException exception) {
// ignored
} catch (IllegalAccessException exception) {
// ignored
} catch (IllegalArgumentException exception) {
// ignored
}
}

static void setPermissionsToOwnerOnlyWindows(File file) throws IOException {
Path path = Paths.get(file.getAbsolutePath());
UserPrincipal owner = path.getFileSystem().getUserPrincipalLookupService()
.lookupPrincipalByName("OWNER@");

// get view
AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class);

// All available entries
Set<AclEntryPermission> permissions = ImmutableSet.of(
AclEntryPermission.APPEND_DATA,
AclEntryPermission.DELETE,
AclEntryPermission.DELETE_CHILD,
AclEntryPermission.READ_ACL,
AclEntryPermission.READ_ATTRIBUTES,
AclEntryPermission.READ_DATA,
AclEntryPermission.READ_NAMED_ATTRS,
AclEntryPermission.SYNCHRONIZE,
AclEntryPermission.WRITE_ACL,
AclEntryPermission.WRITE_ATTRIBUTES,
AclEntryPermission.WRITE_DATA,
AclEntryPermission.WRITE_NAMED_ATTRS,
AclEntryPermission.WRITE_OWNER
);

// create ACL to give owner everything
AclEntry entry = AclEntry.newBuilder()
.setType(AclEntryType.ALLOW)
.setPrincipal(owner)
.setPermissions(permissions)
.build();

// Overwrite the ACL with only this permission
view.setAcl(ImmutableList.of(entry));
}
}