/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.controller.persistence;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.jboss.as.controller.logging.ControllerLogger;
import org.jboss.dmr.ModelNode;
import org.xnio.IoUtils;
/**
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
*/
class FilePersistenceUtils {
static File createTempFile(File fileName) {
return createTempFile(fileName.getParentFile(), fileName.getName());
}
static File createTempFile(File fileFolder, String fileName) {
return new File(fileFolder, fileName + ".tmp");
}
static ExposedByteArrayOutputStream marshalXml(final AbstractConfigurationPersister persister, final ModelNode model) throws ConfigurationPersistenceException {
ExposedByteArrayOutputStream marshalled = new ExposedByteArrayOutputStream(1024 * 8);
try {
try {
BufferedOutputStream output = new BufferedOutputStream(marshalled);
persister.marshallAsXml(model, output);
output.close();
marshalled.close();
} finally {
IoUtils.safeClose(marshalled);
}
} catch (Exception e) {
throw ControllerLogger.ROOT_LOGGER.failedToMarshalConfiguration(e);
}
return marshalled;
}
static void copyFile(final File file, final File backup) throws IOException {
Files.copy(file.toPath(), backup.toPath(), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
}
static void moveTempFileToMain(File tempFileName, File fileName) throws ConfigurationPersistenceException {
//Rename the temp file written to the target file
try {
Files.move(tempFileName.toPath(), fileName.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
throw ControllerLogger.ROOT_LOGGER.failedToRenameTempFile(e, tempFileName, fileName);
}
}
static void deleteFile(File file) {
if (file.exists()) {
if (!file.delete() && file.exists()) {
file.deleteOnExit();
throw new IllegalStateException(ControllerLogger.ROOT_LOGGER.couldNotDeleteFile(file));
}
}
}
static File writeToTempFile(ExposedByteArrayOutputStream marshalled, File tempFileName, File fileName) throws IOException {
Path targetPath = tempFileName.toPath();
deleteFile(tempFileName);
try {
createTempFileWithAttributes(targetPath, fileName);
} catch (IOException ioex) {
ioex.printStackTrace();
}
try (InputStream is = marshalled.getInputStream()) {
Files.copy(is, targetPath, StandardCopyOption.REPLACE_EXISTING);
}
return tempFileName;
}
static Path createTempFileWithAttributes(Path tempFilePath, File fileName) throws IOException {
Path exisitingFilePath = fileName.toPath();
List<FileAttribute> attributes = new ArrayList<>(2);
attributes.addAll(getPosixAttributes(exisitingFilePath));
attributes.addAll(getAclAttributes(exisitingFilePath));
if (!attributes.isEmpty()) {
try {
return Files.createFile(tempFilePath, attributes.toArray(new FileAttribute<?>[attributes.size()]));
} catch (UnsupportedOperationException ex) {
}
}
return Files.createFile(tempFilePath);
}
private static List<FileAttribute<Set<PosixFilePermission>>> getPosixAttributes(Path file) throws IOException {
if (Files.exists(file) && Files.getFileStore(file).supportsFileAttributeView(PosixFileAttributeView.class)) {
PosixFileAttributeView posixView = Files.getFileAttributeView(file, PosixFileAttributeView.class);
if (posixView != null) {
return Collections.singletonList(PosixFilePermissions.asFileAttribute(posixView.readAttributes().permissions()));
}
}
return Collections.emptyList();
}
private static List<FileAttribute<List<AclEntry>>> getAclAttributes(Path file) throws IOException {
if (Files.exists(file) && Files.getFileStore(file).supportsFileAttributeView(AclFileAttributeView.class)) {
AclFileAttributeView aclView = Files.getFileAttributeView(file, AclFileAttributeView.class);
if (aclView != null) {
final List<AclEntry> entries = aclView.getAcl();
return Collections.singletonList(new FileAttribute<List<AclEntry>>() {
@Override
public List<AclEntry> value() {
return entries;
}
@Override
public String name() {
return "acl:acl";
}
});
}
}
return Collections.emptyList();
}
static boolean isParentFolderWritable(File file){
if ( !file.exists() || file.getParentFile() == null ){
return false;
}
return file.getParentFile().canWrite();
}
}