1 5 package org.h2.store; 6 7 import java.io.File ; 8 import java.io.IOException ; 9 import java.io.RandomAccessFile ; 10 import java.lang.ref.Reference ; 11 import java.sql.SQLException ; 12 13 import org.h2.engine.Constants; 14 import org.h2.message.Message; 15 import org.h2.security.SecureFileStore; 16 import org.h2.util.ByteUtils; 17 import org.h2.util.FileUtils; 18 import org.h2.util.TempFileDeleter; 19 20 public class FileStore { 21 22 public static final int HEADER_LENGTH = 3 * Constants.FILE_BLOCK_SIZE; 23 24 protected String name; 25 protected DataHandler handler; 26 private byte[] magic; 27 28 private RandomAccessFile file; 29 private long filePos; 30 private Reference autoDeleteReference; 31 32 public static FileStore open(DataHandler handler, String name, byte[] magic) throws SQLException { 33 return open(handler, name, magic, null, null, 0); 34 } 35 36 public static FileStore open(DataHandler handler, String name, byte[] magic, String cipher, byte[] key) throws SQLException { 37 return open(handler, name, magic, cipher, key, Constants.ENCRYPTION_KEY_HASH_ITERATIONS); 38 } 39 40 public static FileStore open(DataHandler handler, String name, byte[] magic, String cipher, byte[] key, int keyIterations) throws SQLException { 41 FileStore store; 42 if(FileUtils.isInMemory(name)) { 43 store = new MemoryFileStore(handler, name, magic); 44 } else if(cipher == null) { 45 store = new FileStore(handler, name, magic); 46 } else { 47 store = new SecureFileStore(handler, name, magic, cipher, key, keyIterations); 48 } 49 return store; 50 } 51 52 protected FileStore(DataHandler handler, String name, byte[] magic) throws SQLException { 53 this.handler = handler; 54 this.name = name; 55 this.magic = magic; 56 try { 57 FileUtils.createDirs(name); 58 File f = new File (name); 59 if(f.exists() && !f.canWrite()) { 60 file = FileUtils.openRandomAccessFile(name, "r"); 61 } else { 62 file = FileUtils.openRandomAccessFile(name, "rw"); 64 } 65 } catch(IOException e) { 66 throw Message.convert(e); 67 } 68 } 69 70 protected FileStore(DataHandler handler, byte[] magic) { 71 this.handler = handler; 72 this.magic = magic; 73 } 74 75 protected byte[] generateSalt() { 76 return magic; 77 } 78 79 protected void initKey(byte[] salt) { 80 } 82 83 protected void checkWritingAllowed() throws SQLException { 84 if(handler != null) { 85 handler.checkWritingAllowed(); 86 } 87 } 88 89 protected void checkPowerOff() throws SQLException { 90 if(handler != null) { 91 handler.checkPowerOff(); 92 } 93 } 94 95 public void init() throws SQLException { 96 int len = Constants.FILE_BLOCK_SIZE; 97 byte[] salt; 98 if(length() < HEADER_LENGTH) { 99 writeDirect(magic, 0, len); 101 salt = generateSalt(); 102 writeDirect(salt, 0, len); 103 initKey(salt); 104 write(magic, 0, len); 106 } else { 107 seek(0); 109 byte[] buff = new byte[len]; 110 readFullyDirect(buff, 0, len); 111 if(ByteUtils.compareNotNull(buff, magic) != 0) { 112 throw Message.getSQLException(Message.FILE_VERSION_ERROR_1, name); 113 } 114 salt = new byte[len]; 115 readFullyDirect(salt, 0, len); 116 initKey(salt); 117 readFully(buff, 0, Constants.FILE_BLOCK_SIZE); 119 if(ByteUtils.compareNotNull(buff, magic) != 0) { 120 throw Message.getSQLException(Message.FILE_ENCRYPTION_ERROR_1, name); 121 } 122 } 123 } 124 125 public void close() throws IOException { 126 if(file != null) { 127 try { 128 file.close(); 129 } finally { 130 file = null; 131 } 132 } 133 } 134 135 public void closeSilently() { 136 if(file != null) { 137 try { 138 file.close(); 139 } catch(IOException e) { 140 file = null; 141 } 142 } 143 } 144 145 public void closeAndDeleteSilently() { 146 if(file != null) { 147 closeSilently(); 148 TempFileDeleter.deleteFile(autoDeleteReference, name); 149 name = null; 150 } 151 } 152 153 protected void readFullyDirect(byte[] b, int off, int len) throws SQLException { 154 readFully(b, off, len); 155 } 156 157 public void readFully(byte[] b, int off, int len) throws SQLException { 158 if(Constants.CHECK && len < 0) { 159 throw Message.getInternalError("read len "+len); 160 } 161 if(Constants.CHECK && len % Constants.FILE_BLOCK_SIZE != 0) { 162 throw Message.getInternalError("unaligned read "+name+" len "+len); 163 } 164 checkPowerOff(); 165 try { 166 file.readFully(b, off, len); 167 } catch (IOException e) { 168 throw Message.convert(e); 169 } 170 filePos += len; 171 } 172 173 public void seek(long pos) throws SQLException { 174 if(Constants.CHECK && pos % Constants.FILE_BLOCK_SIZE != 0) { 175 throw Message.getInternalError("unaligned seek "+name+" pos "+pos); 176 } 177 try { 178 if(pos != filePos) { 179 file.seek(pos); 180 filePos = pos; 181 } 182 } catch (IOException e) { 183 throw Message.convert(e); 184 } 185 } 186 187 protected void writeDirect(byte[] b, int off, int len) throws SQLException { 188 write(b, off, len); 189 } 190 191 public void write(byte[] b, int off, int len) throws SQLException { 192 if(Constants.CHECK && len < 0) { 193 throw Message.getInternalError("read len "+len); 194 } 195 if(Constants.CHECK && len % Constants.FILE_BLOCK_SIZE != 0) { 196 throw Message.getInternalError("unaligned write "+name+" len "+len); 197 } 198 checkWritingAllowed(); 199 checkPowerOff(); 200 try { 201 file.write(b, off, len); 202 } catch (IOException e) { 203 if(freeUpDiskSpace()) { 204 try { 205 file.write(b, off, len); 206 } catch (IOException e2) { 207 throw Message.convert(e2); 208 } 209 } else { 210 throw Message.convert(e); 211 } 212 } 213 filePos += len; 214 } 215 216 private boolean freeUpDiskSpace() throws SQLException { 217 if(handler == null) { 218 return false; 219 } 220 handler.freeUpDiskSpace(); 221 return true; 222 } 223 224 public void setLength(long newLength) throws SQLException { 225 if(Constants.CHECK && newLength % Constants.FILE_BLOCK_SIZE != 0) { 226 throw Message.getInternalError("unaligned setLength "+name+" pos "+newLength); 227 } 228 checkPowerOff(); 229 checkWritingAllowed(); 230 try { 231 FileUtils.setLength(file, newLength); 232 } catch (IOException e) { 233 if(freeUpDiskSpace()) { 234 try { 235 FileUtils.setLength(file, newLength); 236 } catch (IOException e2) { 237 throw Message.convert(e2); 238 } 239 } else { 240 throw Message.convert(e); 241 } 242 } 243 } 244 245 public long length() throws SQLException { 246 try { 247 if(Constants.CHECK && file.length() % Constants.FILE_BLOCK_SIZE != 0) { 248 long newLength = file.length() + Constants.FILE_BLOCK_SIZE - (file.length() % Constants.FILE_BLOCK_SIZE); 249 FileUtils.setLength(file, newLength); 250 throw Message.getInternalError("unaligned file length "+name+" len "+file.length()); 251 } 252 return file.length(); 253 } catch (IOException e) { 254 throw Message.convert(e); 255 } 256 } 257 258 public long getFilePointer() throws SQLException { 259 if(Constants.CHECK2) { 260 try { 261 if(file.getFilePointer() != filePos) { 262 throw Message.getInternalError(); 263 } 264 } catch (IOException e) { 265 throw Message.convert(e); 266 } 267 } 268 return filePos; 269 } 270 271 public void sync() { 272 try { 273 file.getFD().sync(); 274 } catch(IOException e) { 275 } 277 } 278 279 public void autoDelete() { 280 autoDeleteReference = TempFileDeleter.addFile(name, this); 281 } 282 283 public void stopAutoDelete() { 284 TempFileDeleter.stopAutoDelete(autoDeleteReference, name); 285 autoDeleteReference = null; 286 } 287 288 } 289 | Popular Tags |