/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., 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.patching.runner; import static org.jboss.as.patching.IoUtils.NO_CONTENT; import static org.jboss.as.patching.IoUtils.copy; import static org.jboss.as.patching.IoUtils.safeClose; import java.io.File; import java.io.IOException; import java.io.InputStream; import org.jboss.as.patching.IoUtils; import org.jboss.as.patching.logging.PatchLogger; import org.jboss.as.patching.metadata.ContentModification; import org.jboss.as.patching.metadata.MiscContentItem; /** * Base {@linkplain PatchingTask} for misc file updates. * * @author Emanuel Muckenhuber */ abstract class AbstractFileTask extends AbstractPatchingTask<MiscContentItem> { final File target; // the target file final File backup; // the backup file protected AbstractFileTask(PatchingTaskDescription description, File target, File backup) { super(description, MiscContentItem.class); this.target = target; this.backup = backup; } /** * Create the rollback item. * * @param original the original content modification * @param item the new misc content item * @param targetHash the new target hash * @return the rollback modification item */ abstract ContentModification createRollbackEntry(ContentModification original, MiscContentItem item, byte[] targetHash); @Override byte[] backup(PatchingTaskContext context) throws IOException { if(target.isFile()) { // Backup the original in the history directory final byte[] backupHash = IoUtils.copy(target, backup); return backupHash; } else if (contentItem.isDirectory() && target.isDirectory()) { // Completely ignore the apply step if the directory already exists // This will basically skip the creation of the rollback item setIgnoreApply(); } return NO_CONTENT; } @Override byte[] apply(PatchingTaskContext context, PatchContentLoader loader) throws IOException { final MiscContentItem item = contentItem; if(item.isDirectory()) { if(! target.mkdirs() && ! target.isDirectory()) { throw PatchLogger.ROOT_LOGGER.cannotCreateDirectory(target.getAbsolutePath()); } return NO_CONTENT; } else { if (!target.exists()) { createParentDirectories(target, item.getPath(), item.getPath().length, context); } final InputStream is = loader.openContentStream(item); try { // Replace the file return copy(is, target); } finally { safeClose(is); } } } @Override ContentModification createRollbackEntry(ContentModification original, byte[] targetHash, byte[] itemHash) { final MiscContentItem item = new MiscContentItem(contentItem.getName(), contentItem.getPath(), itemHash, contentItem.isDirectory(), contentItem.isAffectsRuntime()); return createRollbackEntry(original, item, targetHash); } static void createParentDirectories(final File target, String[] path, int depth, final PatchingTaskContext context) throws IOException { if (depth > 0) { final File parent = target.getParentFile(); if (! parent.exists()) { createParentDirectories(parent, path, depth - 1, context); } if(! parent.mkdir() && ! parent.isDirectory()) { throw PatchLogger.ROOT_LOGGER.cannotCreateDirectory(target.getAbsolutePath()); } // TODO record changes // final String[] newPath = Arrays.copyOf(path, depth - 1); // final MiscContentItem item = new MiscContentItem(parent.getName(), newPath, NO_CONTENT); // context.recordChange(new ContentModification(item, NO_CONTENT, ModificationType.ADD), new ContentModification(item, NO_CONTENT, ModificationType.REMOVE)); } } }