|
1 /******************************************************************************* |
|
2 * Copyright (c) 2000, 2006 IBM Corporation and others. |
|
3 * All rights reserved. This program and the accompanying materials |
|
4 * are made available under the terms of the Eclipse Public License v1.0 |
|
5 * which accompanies this distribution, and is available at |
|
6 * http://www.eclipse.org/legal/epl-v10.html |
|
7 * |
|
8 * Contributors: |
|
9 * IBM Corporation - initial API and implementation |
|
10 *******************************************************************************/ |
|
11 package org.eclipse.core.internal.localstore; |
|
12 |
|
13 import java.io.*; |
|
14 import org.eclipse.core.internal.utils.FileUtil; |
|
15 |
|
16 /** |
|
17 * This class should be used when there's a file already in the |
|
18 * destination and we don't want to lose its contents if a |
|
19 * failure writing this stream happens. |
|
20 * Basically, the new contents are written to a temporary location. |
|
21 * If everything goes OK, it is moved to the right place. |
|
22 * The user has the option to define the temporary location or |
|
23 * it will be created in the default-temporary directory |
|
24 * (see java.io.File for details). |
|
25 */ |
|
26 public class SafeFileOutputStream extends OutputStream { |
|
27 protected File temp; |
|
28 protected File target; |
|
29 protected OutputStream output; |
|
30 protected boolean failed; |
|
31 protected static final String EXTENSION = ".bak"; //$NON-NLS-1$ |
|
32 |
|
33 public SafeFileOutputStream(File file) throws IOException { |
|
34 this(file.getAbsolutePath(), null); |
|
35 } |
|
36 |
|
37 /** |
|
38 * If targetPath is null, the file will be created in the default-temporary directory. |
|
39 */ |
|
40 public SafeFileOutputStream(String targetPath, String tempPath) throws IOException { |
|
41 failed = false; |
|
42 target = new File(targetPath); |
|
43 createTempFile(tempPath); |
|
44 if (!target.exists()) { |
|
45 if (!temp.exists()) { |
|
46 output = new BufferedOutputStream(new FileOutputStream(target)); |
|
47 return; |
|
48 } |
|
49 // If we do not have a file at target location, but we do have at temp location, |
|
50 // it probably means something wrong happened the last time we tried to write it. |
|
51 // So, try to recover the backup file. And, if successful, write the new one. |
|
52 copy(temp, target); |
|
53 } |
|
54 output = new BufferedOutputStream(new FileOutputStream(temp)); |
|
55 } |
|
56 |
|
57 public void close() throws IOException { |
|
58 try { |
|
59 output.close(); |
|
60 } catch (IOException e) { |
|
61 failed = true; |
|
62 throw e; // rethrow |
|
63 } |
|
64 if (failed) |
|
65 temp.delete(); |
|
66 else |
|
67 commit(); |
|
68 } |
|
69 |
|
70 protected void commit() throws IOException { |
|
71 if (!temp.exists()) |
|
72 return; |
|
73 target.delete(); |
|
74 copy(temp, target); |
|
75 temp.delete(); |
|
76 } |
|
77 |
|
78 protected void copy(File sourceFile, File destinationFile) throws IOException { |
|
79 if (!sourceFile.exists()) |
|
80 return; |
|
81 if (sourceFile.renameTo(destinationFile)) |
|
82 return; |
|
83 InputStream source = null; |
|
84 OutputStream destination = null; |
|
85 try { |
|
86 source = new BufferedInputStream(new FileInputStream(sourceFile)); |
|
87 destination = new BufferedOutputStream(new FileOutputStream(destinationFile)); |
|
88 transferStreams(source, destination); |
|
89 } finally { |
|
90 FileUtil.safeClose(source); |
|
91 FileUtil.safeClose(destination); |
|
92 } |
|
93 } |
|
94 |
|
95 protected void createTempFile(String tempPath) { |
|
96 if (tempPath == null) |
|
97 tempPath = target.getAbsolutePath() + EXTENSION; |
|
98 temp = new File(tempPath); |
|
99 } |
|
100 |
|
101 public void flush() throws IOException { |
|
102 try { |
|
103 output.flush(); |
|
104 } catch (IOException e) { |
|
105 failed = true; |
|
106 throw e; // rethrow |
|
107 } |
|
108 } |
|
109 |
|
110 public String getTempFilePath() { |
|
111 return temp.getAbsolutePath(); |
|
112 } |
|
113 |
|
114 protected void transferStreams(InputStream source, OutputStream destination) throws IOException { |
|
115 byte[] buffer = new byte[8192]; |
|
116 while (true) { |
|
117 int bytesRead = source.read(buffer); |
|
118 if (bytesRead == -1) |
|
119 break; |
|
120 destination.write(buffer, 0, bytesRead); |
|
121 } |
|
122 } |
|
123 |
|
124 public void write(int b) throws IOException { |
|
125 try { |
|
126 output.write(b); |
|
127 } catch (IOException e) { |
|
128 failed = true; |
|
129 throw e; // rethrow |
|
130 } |
|
131 } |
|
132 } |