/**
* Copyright (C) 2010-2017 Structr GmbH
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Structr. If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.files.ssh.filesystem;
import java.io.IOException;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.GroupPrincipal;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.UserPrincipal;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import org.structr.core.app.StructrApp;
import org.structr.core.entity.AbstractNode;
import org.structr.core.entity.Group;
import org.structr.core.entity.Principal;
import org.structr.core.graph.Tx;
import org.structr.web.entity.AbstractFile;
import org.structr.web.entity.FileBase;
import org.structr.web.entity.Folder;
import org.structr.web.entity.User;
/**
*
*/
public class StructrFileAttributes implements PosixFileAttributes, DosFileAttributes, PosixFileAttributeView {
private static final Logger logger = LoggerFactory.getLogger(StructrFileAttributes.class.getName());
public static final Set<String> SUPPORTED_VIEWS = new LinkedHashSet<>(Arrays.asList(new String[] { "owner", "dos", "basic", "posix", "permissions" } ));
private SecurityContext securityContext = null;
private AbstractFile file = null;
public StructrFileAttributes(final SecurityContext securityContext, final AbstractFile file) {
this.securityContext = securityContext;
this.file = file;
}
@Override
public UserPrincipal owner() {
if (file == null) {
return null;
}
UserPrincipal owner = null;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
final Principal fileOwner = file.getOwnerNode();
if (fileOwner == null) {
owner = securityContext.getUser(false)::getName;
} else {
owner = fileOwner::getName;
}
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return owner;
}
@Override
public GroupPrincipal group() {
if (file == null) {
return null;
}
final List<Group> groups = new LinkedList<>();
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
final Principal owner = file.getOwnerNode();
if (owner != null) {
groups.addAll(owner.getProperty(User.groups));
}
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return groups.size() > 0 ? groups.get(0)::getName : null;
}
@Override
public FileTime lastModifiedTime() {
if (file == null) {
return null;
}
FileTime time = null;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
final Date date = file.getLastModifiedDate();
if (date != null) {
time = FileTime.fromMillis(date.getTime());
}
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return time;
}
@Override
public FileTime lastAccessTime() {
return lastModifiedTime();
}
@Override
public FileTime creationTime() {
if (file == null) {
return null;
}
FileTime time = null;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
final Date date = file.getCreatedDate();
if (date != null) {
time = FileTime.fromMillis(date.getTime());
}
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return time;
}
@Override
public boolean isRegularFile() {
if (file == null) {
return false;
}
boolean isRegularFile = false;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
isRegularFile = file.getProperty(FileBase.isFile);
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return isRegularFile;
}
@Override
public boolean isDirectory() {
if (file == null) {
return false;
}
boolean isDirectory = false;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
isDirectory = file.getProperty(Folder.isFolder);
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return isDirectory;
}
@Override
public boolean isSymbolicLink() {
// Structr doesn't support symbolic links yet
return false;
}
@Override
public boolean isOther() {
return false;
}
@Override
public long size() {
if (file == null) {
return 0L;
}
long size = 0;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
final Number s = file.getProperty(FileBase.size);
if (s != null) {
size = s.longValue();
}
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return size;
}
@Override
public Object fileKey() {
if (file == null) {
return null;
}
String uuid = null;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
uuid = file.getUuid();
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return uuid;
}
@Override
public Set<PosixFilePermission> permissions() {
final Set<PosixFilePermission> permissions = new HashSet<>();
permissions.add(PosixFilePermission.OWNER_READ);
permissions.add(PosixFilePermission.OWNER_WRITE);
if (file != null) {
if (file instanceof Folder) {
permissions.add(PosixFilePermission.OWNER_EXECUTE);
}
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
if (file.isVisibleToPublicUsers()) {
permissions.add(PosixFilePermission.OTHERS_READ);
permissions.add(PosixFilePermission.OTHERS_WRITE);
if (file instanceof Folder) {
permissions.add(PosixFilePermission.OTHERS_EXECUTE);
}
}
if (file.isVisibleToAuthenticatedUsers()) {
permissions.add(PosixFilePermission.GROUP_READ);
permissions.add(PosixFilePermission.GROUP_WRITE);
if (file instanceof Folder) {
permissions.add(PosixFilePermission.GROUP_EXECUTE);
}
}
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
}
return permissions;
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public boolean isHidden() {
return false;
}
@Override
public boolean isArchive() {
return false;
}
@Override
public boolean isSystem() {
return false;
}
public Map<String, Object> toMap(final String filter) {
final Map<String, Object> map = new HashMap<>();
final String prefix = filter.substring(0, filter.indexOf(":"));
final GroupPrincipal group = group();
final UserPrincipal owner = owner();
if ("dos".equals(prefix)) {
map.put("hidden", isHidden());
map.put("archive", isArchive());
map.put("system", isSystem());
map.put("readonly", isReadOnly());
}
if (!"owner".equals(prefix)) {
map.put("lastModifiedTime", lastModifiedTime());
map.put("lastAccessTime", lastAccessTime());
map.put("creationTime", creationTime());
map.put("size", size());
map.put("isRegularFile", isRegularFile());
map.put("isDirectory", isDirectory());
map.put("isSymbolicLink", isSymbolicLink());
map.put("isOther", isOther());
map.put("fileKey", fileKey());
}
// POSIX properties
if ("posix".equals(prefix)) {
map.put("permissions", permissions());
if (group != null) {
map.put("group", group.getName());
}
if (owner != null) {
map.put("owner", owner.getName());
// set group to owner
if (group == null) {
map.put("group", owner.getName());
}
}
}
// permissions only
if ("permissions".equals(prefix)) {
map.put("permissions", permissions());
}
if ("owner".equals(prefix) && owner != null) {
map.put("owner", owner().getName());
}
return map;
}
// ----- interface PosixFileAttributeView -----
@Override
public String name() {
if (file == null) {
return null;
}
String name = null;
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
name = file.getName();
tx.success();
} catch (FrameworkException fex) {
logger.error("", fex);
}
return name;
}
@Override
public PosixFileAttributes readAttributes() throws IOException {
return this;
}
@Override
public void setPermissions(final Set<PosixFilePermission> perms) throws IOException {
if (file == null) {
return;
}
try (Tx tx = StructrApp.getInstance(securityContext).tx()) {
file.setProperty(AbstractNode.visibleToAuthenticatedUsers, perms.contains(PosixFilePermission.GROUP_READ));
file.setProperty(AbstractNode.visibleToPublicUsers, perms.contains(PosixFilePermission.OTHERS_READ));
tx.success();
} catch (FrameworkException fex) {
logger.error("Unable to set mapped file permissions for " + file, fex);
}
}
@Override
public void setGroup(final GroupPrincipal group) throws IOException {
}
@Override
public void setTimes(final FileTime lastModifiedTime, final FileTime lastAccessTime, final FileTime createTime) throws IOException {
}
@Override
public UserPrincipal getOwner() throws IOException {
return owner();
}
@Override
public void setOwner(final UserPrincipal owner) throws IOException {
}
}