001: /*
002: * BufferSaveRequest.java - I/O request
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2000, 2005 Slava Pestov
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022:
023: package org.gjt.sp.jedit.bufferio;
024:
025: //{{{ Imports
026: import java.io.*;
027: import java.util.zip.*;
028:
029: import org.gjt.sp.jedit.io.*;
030: import org.gjt.sp.jedit.*;
031: import org.gjt.sp.util.*;
032: import java.nio.charset.UnsupportedCharsetException;
033:
034: //}}}
035:
036: /**
037: * A buffer save request.
038: * @author Slava Pestov
039: * @version $Id: BufferSaveRequest.java 11128 2007-11-24 08:32:21Z k_satoda $
040: */
041: public class BufferSaveRequest extends BufferIORequest {
042: //{{{ BufferSaveRequest constructor
043: /**
044: * Creates a new buffer I/O request.
045: * @param view The view
046: * @param buffer The buffer
047: * @param session The VFS session
048: * @param vfs The VFS
049: * @param path The path
050: */
051: public BufferSaveRequest(View view, Buffer buffer, Object session,
052: VFS vfs, String path) {
053: super (view, buffer, session, vfs, path);
054: } //}}}
055:
056: //{{{ run() method
057: public void run() {
058: /* if the VFS supports renaming files, we first
059: * save to #<filename>#save#, then rename that
060: * to <filename>, so that if the save fails,
061: * data will not be lost.
062: *
063: * as of 4.1pre7 we now call vfs.getTwoStageSaveName()
064: * instead of constructing the path directly
065: * since some VFS's might not allow # in filenames.
066: */
067:
068: boolean vfsRenameCap = (vfs.getCapabilities() & VFS.RENAME_CAP) != 0;
069:
070: boolean wantTwoStage = wantTwoStageSave(buffer);
071: boolean twoStageSave = vfsRenameCap && wantTwoStage;
072:
073: try {
074: String[] args = { vfs.getFileName(path) };
075: setStatus(jEdit.getProperty("vfs.status.save", args));
076:
077: // the entire save operation can be aborted...
078: setAbortable(true);
079:
080: path = vfs._canonPath(session, path, view);
081: if (!MiscUtilities.isURL(path))
082: path = MiscUtilities.resolveSymlinks(path);
083:
084: String savePath;
085: if (twoStageSave) {
086: savePath = vfs.getTwoStageSaveName(path);
087: if (savePath == null) {
088: throw new IOException(
089: "Can't get a temporary path for two-stage save: "
090: + path);
091: }
092: } else {
093: makeBackup();
094: savePath = path;
095: }
096:
097: OutputStream out = vfs._createOutputStream(session,
098: savePath, view);
099: if (out == null) {
100: buffer.setBooleanProperty(ERROR_OCCURRED, true);
101: return;
102: }
103: try {
104: // this must be after the stream is created or
105: // we deadlock with SSHTools.
106: buffer.readLock();
107: try {
108: // Can't use buffer.getName() here because
109: // it is not changed until the save is
110: // complete
111: if (path.endsWith(".gz"))
112: buffer.setBooleanProperty(Buffer.GZIPPED, true);
113: else if (buffer.getName().endsWith(".gz")) {
114: // The path do not ends with gz.
115: // The buffer name was .gz.
116: // So it means it's blabla.txt.gz -> blabla.txt, I remove
117: // the gz property
118: buffer
119: .setBooleanProperty(Buffer.GZIPPED,
120: false);
121: }
122:
123: if (buffer.getBooleanProperty(Buffer.GZIPPED))
124: out = new GZIPOutputStream(out);
125:
126: write(buffer, out);
127: } finally {
128: buffer.readUnlock();
129: }
130: } finally {
131: IOUtilities.closeQuietly(out);
132: }
133:
134: if (twoStageSave) {
135: makeBackup();
136: if (!vfs._rename(session, savePath, path, view))
137: throw new IOException("Rename failed: " + savePath);
138: }
139:
140: if (!twoStageSave)
141: VFSManager.sendVFSUpdate(vfs, path, true);
142: } catch (UnsupportedCharsetException e) {
143: Log.log(Log.ERROR, this , e, e);
144: String[] pp = { e.getCharsetName() };
145: VFSManager.error(view, path,
146: "ioerror.unsupported-encoding-error", pp);
147:
148: buffer.setBooleanProperty(ERROR_OCCURRED, true);
149: } catch (Exception e) {
150: Log.log(Log.ERROR, this , e);
151: String[] pp = { e.toString() };
152: VFSManager.error(view, path, "ioerror.write-error", pp);
153:
154: buffer.setBooleanProperty(ERROR_OCCURRED, true);
155: } catch (WorkThread.Abort a) {
156: buffer.setBooleanProperty(ERROR_OCCURRED, true);
157: } finally {
158: try {
159: vfs._saveComplete(session, buffer, path, view);
160: if (twoStageSave) {
161: vfs
162: ._finishTwoStageSave(session, buffer, path,
163: view);
164: }
165: // clean up left-over markers file
166: if (!jEdit.getBooleanProperty("persistentMarkers"))
167: vfs._delete(session, Buffer.getMarkersPath(vfs,
168: path), view);
169: vfs._endVFSSession(session, view);
170: } catch (Exception e) {
171: Log.log(Log.ERROR, this , e);
172: String[] pp = { e.toString() };
173: VFSManager.error(view, path, "ioerror.write-error", pp);
174:
175: buffer.setBooleanProperty(ERROR_OCCURRED, true);
176: } catch (WorkThread.Abort a) {
177: buffer.setBooleanProperty(ERROR_OCCURRED, true);
178: }
179: }
180: } //}}}
181:
182: //{{{ Private members
183:
184: //{{{ makeBackup() method
185: /**
186: * Make the backup.
187: */
188: private void makeBackup() throws IOException {
189: // Only backup once per session
190: if (buffer.getProperty(Buffer.BACKED_UP) == null
191: || jEdit.getBooleanProperty("backupEverySave")) {
192: vfs._backup(session, path, view);
193: buffer.setBooleanProperty(Buffer.BACKED_UP, true);
194: }
195: } //}}}
196:
197: //{{{ wantTwoStageSave() method
198: private static boolean wantTwoStageSave(Buffer buffer) {
199: return !buffer.getBooleanProperty("forbidTwoStageSave")
200: && (buffer.getBooleanProperty("overwriteReadonly") || jEdit
201: .getBooleanProperty("twoStageSave"));
202: }//}}}
203:
204: //}}}
205: }
|