/* * BufferSaveRequest.java - I/O request * :tabSize=4:indentSize=4:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 2000, 2005 Slava Pestov * * This program 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 2 * of the License, or any later version. * * This program 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.gjt.sp.jedit.bufferio; //{{{ Imports import java.io.*; import java.io.Closeable; import java.util.zip.*; import org.gjt.sp.jedit.io.*; import org.gjt.sp.jedit.*; import org.gjt.sp.util.*; import java.nio.charset.UnsupportedCharsetException; //}}} /** * A buffer save request. * @author Slava Pestov * @version $Id: BufferSaveRequest.java 22357 2012-10-13 04:58:01Z ezust $ */ public class BufferSaveRequest extends BufferIORequest { //{{{ BufferSaveRequest constructor /** * Creates a new buffer I/O request. * @param view The view * @param buffer The buffer * @param session The VFS session * @param vfs The VFS * @param path The path */ public BufferSaveRequest(View view, Buffer buffer, Object session, VFS vfs, String path) { super(view,buffer,session,vfs,path); } //}}} //{{{ run() method public void _run() { /* if the VFS supports renaming files, we first * save to #<filename>#save#, then rename that * to <filename>, so that if the save fails, * data will not be lost. * * as of 4.1pre7 we now call vfs.getTwoStageSaveName() * instead of constructing the path directly * since some VFS's might not allow # in filenames. */ boolean vfsRenameCap = (vfs.getCapabilities() & VFS.RENAME_CAP) != 0; boolean wantTwoStage = wantTwoStageSave(buffer); boolean twoStageSave = vfsRenameCap && wantTwoStage; try { String[] args = { vfs.getFileName(path) }; setStatus(jEdit.getProperty("vfs.status.save",args)); // the entire save operation can be aborted... setCancellable(true); path = vfs._canonPath(session,path,view); if(!MiscUtilities.isURL(path)) path = MiscUtilities.resolveSymlinks(path); String savePath; if(twoStageSave) { savePath = vfs.getTwoStageSaveName(path); if (savePath == null) { throw new IOException( "Can't get a temporary path for two-stage save: " + path); } } else { makeBackup(); savePath = path; } OutputStream out = vfs._createOutputStream(session,savePath,view); if(out == null) { buffer.setBooleanProperty(ERROR_OCCURRED,true); return; } try { // this must be after the stream is created or // we deadlock with SSHTools. buffer.readLock(); try { // Can't use buffer.getName() here because // it is not changed until the save is // complete if(path.endsWith(".gz")) buffer.setBooleanProperty(Buffer.GZIPPED,true); else if (buffer.getName().endsWith(".gz")) { // The path do not ends with gz. // The buffer name was .gz. // So it means it's blabla.txt.gz -> blabla.txt, I remove // the gz property buffer.setBooleanProperty(Buffer.GZIPPED, false); } if(buffer.getBooleanProperty(Buffer.GZIPPED)) out = new GZIPOutputStream(out); write(buffer,out); } finally { buffer.readUnlock(); } } catch(InterruptedException e) { buffer.setBooleanProperty(ERROR_OCCURRED,true); Thread.currentThread().interrupt(); } finally { IOUtilities.closeQuietly((Closeable)out); } if(twoStageSave) { makeBackup(); if(!vfs._rename(session,savePath,path,view)) throw new IOException("Rename failed: " + savePath); } if(!twoStageSave) VFSManager.sendVFSUpdate(vfs,path,true); } catch (FileNotFoundException e) { Log.log(Log.ERROR,this,"Unable to save buffer " + e); String[] pp = { e.getMessage() }; VFSManager.error(view,path,"ioerror.write-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } catch(UnsupportedCharsetException e) { Log.log(Log.ERROR, this, e, e); String[] pp = { e.getCharsetName() }; VFSManager.error(view,path,"ioerror.unsupported-encoding-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } catch(Exception e) { Log.log(Log.ERROR,this,e); String[] pp = { e.toString() }; VFSManager.error(view,path,"ioerror.write-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } finally { try { vfs._saveComplete(session,buffer,path,view); if( twoStageSave ) { vfs._finishTwoStageSave(session,buffer,path,view); } // clean up left-over markers file if(!jEdit.getBooleanProperty("persistentMarkers")) vfs._delete(session,Buffer.getMarkersPath(vfs, path),view); vfs._endVFSSession(session,view); } catch(Exception e) { Log.log(Log.ERROR,this,e); String[] pp = { e.toString() }; VFSManager.error(view,path,"ioerror.write-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } } } //}}} //{{{ Private members //{{{ makeBackup() method /** * Make the backup. */ private void makeBackup() { try { // Only backup once per session if(buffer.getProperty(Buffer.BACKED_UP) == null || jEdit.getBooleanProperty("backupEverySave")) { if (jEdit.getIntegerProperty("backups",1) > 0) vfs._backup(session,path,view); buffer.setBooleanProperty(Buffer.BACKED_UP, true); } } catch (IOException ioe) { // Backup failure shouldn't stop caller's activity, like // saving a buffer, so catching the exception. // Most backup failures are reported directly in _backup, // with lesser severity. // Only rare cases manifest with IOException, like #3574500 String[] pp = { ioe.getMessage() }; VFSManager.error(view,path,"ioerror.backup-failed",pp); } } //}}} //{{{ wantTwoStageSave() method private static boolean wantTwoStageSave(Buffer buffer) { return !buffer.getBooleanProperty("forbidTwoStageSave") && (buffer.getBooleanProperty("overwriteReadonly") || jEdit.getBooleanProperty("twoStageSave")); }//}}} //}}} }