1 /******************************************************************************* 2 * Copyright (c) 2003, 2006 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 15 package org.eclipse.osgi.framework.internal.reliablefile; 16 17 import java.io.*; 18 import java.util.zip.Checksum; 19 20 /** 21 * A ReliableFile FileOutputStream replacement class. 22 * This class can be used just like FileOutputStream. The class 23 * is in partnership with ReliableFileInputStream to avoid losing 24 * file data by using multiple files. 25 * 26 * @see ReliableFileInputStream 27 */ 28 public class ReliableFileOutputStream extends FilterOutputStream { 29 /** 30 * ReliableFile object for the file. 31 */ 32 private ReliableFile reliable; 33 34 /** 35 * Checksum calculator 36 */ 37 private Checksum crc; 38 39 private boolean outputOpen = false; 40 41 /** 42 * Constructs a new ReliableFileOutputStream on the File <code>file</code>. If the 43 * file exists, it is written over. See the constructor which can append to 44 * the file if so desired. 45 * 46 * @param file the File on which to stream reads. 47 * @exception java.io.IOException If an error occurs opening the file. 48 */ ReliableFileOutputStream(File file)49 public ReliableFileOutputStream(File file) throws IOException { 50 this(ReliableFile.getReliableFile(file), false); 51 } 52 53 /** 54 * Constructs a new ReliableFileOutputStream on the File <code>file</code>. 55 * 56 * @param file the File on which to stream reads. 57 * @param append a boolean indicating whether or not to append to an existing file. 58 * @exception java.io.IOException If an error occurs opening the file. 59 */ ReliableFileOutputStream(File file, boolean append)60 public ReliableFileOutputStream(File file, boolean append) throws IOException { 61 this(ReliableFile.getReliableFile(file), append); 62 } 63 64 /** 65 * Constructs a new ReliableFileOutputStream on the file named <code>name</code>. If 66 * the file exists, it is written over. See the constructor which can append to 67 * the file if so desired. 68 * The <code>name</code> may be absolute or relative 69 * to the System property <code>"user.dir"</code>. 70 * 71 * @param name the file on which to stream writes. 72 * @exception java.io.IOException If an error occurs opening the file. 73 */ ReliableFileOutputStream(String name)74 public ReliableFileOutputStream(String name) throws IOException { 75 this(ReliableFile.getReliableFile(name), false); 76 } 77 78 /** 79 * Constructs a new ReliableFileOutputStream on the file named <code>name</code>. 80 * The <code>name</code> may be absolute or relative 81 * to the System property <code>"user.dir"</code>. 82 * 83 * @param name the file on which to stream writes. 84 * @param append a boolean indicating whether or not to append to an existing file. 85 * @exception java.io.IOException If an error occurs opening the file. 86 */ ReliableFileOutputStream(String name, boolean append)87 public ReliableFileOutputStream(String name, boolean append) throws IOException { 88 this(ReliableFile.getReliableFile(name), append); 89 } 90 91 /** 92 * Private constructor used by other constructors. 93 * 94 * @param reliable the ReliableFile on which to read. 95 * @param append a boolean indicating whether or not to append to an existing file. 96 * @exception java.io.IOException If an error occurs opening the file. 97 */ ReliableFileOutputStream(ReliableFile reliable, boolean append)98 private ReliableFileOutputStream(ReliableFile reliable, boolean append) throws IOException { 99 super(reliable.getOutputStream(append, ReliableFile.GENERATION_LATEST)); 100 101 this.reliable = reliable; 102 outputOpen = true; 103 if (append) 104 crc = reliable.getFileChecksum(); 105 else 106 crc = reliable.getChecksumCalculator(); 107 } 108 109 /** 110 * Closes this output stream and releases any system resources 111 * associated with this stream. The general contract of <code>close</code> 112 * is that it closes the output stream. A closed stream cannot perform 113 * output operations and cannot be reopened. 114 * 115 * @exception java.io.IOException If an error occurs closing the file. 116 */ 117 @Override close()118 public synchronized void close() throws IOException { 119 closeIntermediateFile(); 120 reliable.closeOutputFile(crc); 121 // if the previouse closeOutpuFile() throws exception, 122 // we don't null out reliable to give another opportunity 123 // to rename the file. 124 reliable = null; 125 } 126 closeIntermediateFile()127 public File closeIntermediateFile() throws IOException { 128 if (reliable == null) 129 throw new IOException("ReliableFile stream not open"); //$NON-NLS-1$ 130 if (outputOpen) { 131 // tag on our signature and checksum 132 reliable.writeChecksumSignature(out, crc); 133 out.flush(); 134 try { 135 ((FileOutputStream) out).getFD().sync(); 136 } catch (IOException e) { 137 // just ignore this Exception 138 //Debug 139 e.printStackTrace(); 140 } 141 out.close(); 142 outputOpen = false; 143 } 144 return reliable.getOutputFile(); 145 } 146 147 /** 148 * Override default FilterOutputStream method. 149 * @see FilterOutputStream#write(byte[]) 150 */ 151 @Override write(byte[] b)152 public void write(byte[] b) throws IOException { 153 this.write(b, 0, b.length); 154 } 155 156 /** 157 * Override default FilterOutputStream method. 158 * @see FilterOutputStream#write(byte[], int, int) 159 */ 160 @Override write(byte[] b, int off, int len)161 public void write(byte[] b, int off, int len) throws IOException { 162 out.write(b, off, len); 163 crc.update(b, off, len); 164 } 165 166 /** 167 * Override default FilterOutputStream method. 168 * @see FilterOutputStream#write(int) 169 */ 170 @Override write(int b)171 public void write(int b) throws IOException { 172 out.write(b); 173 crc.update((byte) b); 174 } 175 abort()176 public void abort() { 177 if (reliable == null) 178 return; 179 if (outputOpen) { 180 try { 181 out.close(); 182 } catch (IOException e) {/*ignore*/ 183 } 184 outputOpen = false; 185 } 186 reliable.abortOutputFile(); 187 reliable = null; 188 } 189 } 190