/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * muCommander 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.job.impl; import java.io.IOException; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.FileFactory; import com.mucommander.commons.file.FileOperation; import com.mucommander.commons.file.util.FileSet; import com.mucommander.commons.io.BufferPool; import com.mucommander.commons.io.RandomAccessOutputStream; import com.mucommander.job.FileCollisionChecker; import com.mucommander.job.FileJob; import com.mucommander.job.FileJobAction; import com.mucommander.job.FileJobState; import com.mucommander.text.Translator; import com.mucommander.ui.dialog.file.FileCollisionDialog; import com.mucommander.ui.dialog.file.ProgressDialog; import com.mucommander.ui.main.MainFrame; /** * This FileJob creates a new file or directory. * * @author Maxence Bernard */ public class MkdirJob extends FileJob { private static final Logger LOGGER = LoggerFactory.getLogger(MkdirJob.class); private AbstractFile destFolder; private boolean mkfileMode; private long allocateSpace; /** * Creates a new MkdirJob which operates in 'mkdir' mode. */ public MkdirJob(ProgressDialog progressDialog, MainFrame mainFrame, FileSet fileSet) { super(progressDialog, mainFrame, fileSet); this.destFolder = fileSet.getBaseFolder(); this.mkfileMode = false; setAutoUnmark(false); } /** * Creates a new MkdirJob which operates in 'mkfile' mode. * * @param allocateSpace number of bytes to allocate to the file, -1 for none (use AbstractFile#mkfile()) */ public MkdirJob(ProgressDialog progressDialog, MainFrame mainFrame, FileSet fileSet, long allocateSpace) { super(progressDialog, mainFrame, fileSet); this.destFolder = fileSet.getBaseFolder(); this.mkfileMode = true; this.allocateSpace = allocateSpace; setAutoUnmark(false); } //////////////////////////// // FileJob implementation // //////////////////////////// /** * Creates the new directory in the destination folder. */ @Override protected boolean processFile(AbstractFile file, Object recurseParams) { // Stop if interrupted (although there is no way to stop the job at this time) if (getState() == FileJobState.INTERRUPTED) return false; do { try { LOGGER.debug("Creating "+file); // Check for file collisions, i.e. if the file already exists in the destination int collision = FileCollisionChecker.checkForCollision(null, file); if(collision!=FileCollisionChecker.NO_COLLOSION) { // File already exists in destination, ask the user what to do (cancel, overwrite,...) but // do not offer the multiple files mode options such as 'skip' and 'apply to all'. int choice = waitForUserResponse(new FileCollisionDialog(getMainFrame(), getMainFrame(), collision, null, file, false, false)); // Overwrite file if (choice==FileCollisionDialog.OVERWRITE_ACTION) { // Delete the file file.delete(); } // Cancel or dialog close (return) // else if (choice==-1 || choice==FileCollisionDialog.CANCEL_ACTION) { else { interrupt(); return false; } } // Create file if(mkfileMode) { // Use mkfile if(allocateSpace==-1) { file.mkfile(); } // Allocate the requested number of bytes else { OutputStream mkfileOut = null; try { // using RandomAccessOutputStream if we can have one if(file.isFileOperationSupported(FileOperation.RANDOM_WRITE_FILE)) { mkfileOut = file.getRandomAccessOutputStream(); ((RandomAccessOutputStream)mkfileOut).setLength(allocateSpace); } // manually otherwise else { mkfileOut = file.getOutputStream(); // Use BufferPool to avoid excessive memory allocation and garbage collection byte buffer[] = BufferPool.getByteArray(); int bufferSize = buffer.length; try { long remaining = allocateSpace; int nbWrite; while (remaining>0 && getState() != FileJobState.INTERRUPTED) { nbWrite = (int)(remaining>bufferSize?bufferSize:remaining); mkfileOut.write(buffer, 0, nbWrite); remaining -= nbWrite; } } finally { BufferPool.releaseByteArray(buffer); } } } finally { if(mkfileOut!=null) try { mkfileOut.close(); } catch(IOException e) {} } } } // Create directory else { file.mkdir(); } // Resolve new file instance now that it exists: remote files do not update file attributes after // creation, we need to get an instance that reflects the newly created file attributes file = FileFactory.getFile(file.getURL()); // Select newly created file when job is finished selectFileWhenFinished(file); return true; // Return Success } catch(IOException e) { // In mkfile mode, interrupting the job will close the OutputStream and cause an IOException to be // thrown, this is normal behavior if (mkfileMode && getState() == FileJobState.INTERRUPTED) return false; LOGGER.debug("IOException caught", e); int action = showErrorDialog( Translator.get("error"), Translator.get(mkfileMode?"cannot_write_file":"cannot_create_folder", file.getAbsolutePath()), new String[]{FileJobAction.RETRY_TEXT, FileJobAction.CANCEL_TEXT}, new int[]{FileJobAction.RETRY, FileJobAction.CANCEL} ); // Retry (loop) if(action==FileJobAction.RETRY) continue; // Cancel action return false; // Return Failure } } while(true); } /** * Folders only needs to be refreshed if it is the destination folder */ @Override protected boolean hasFolderChanged(AbstractFile folder) { return destFolder.equalsCanonical(folder); } //////////////////////// // Overridden methods // //////////////////////// @Override public String getStatusString() { return Translator.get("creating_file", getCurrentFilename()); } }