1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import java.io.File; 20 import java.io.IOException; 21 22 public class JournaledFile { 23 File mReal; 24 File mTemp; 25 boolean mWriting; 26 JournaledFile(File real, File temp)27 public JournaledFile(File real, File temp) { 28 mReal = real; 29 mTemp = temp; 30 } 31 32 /** Returns the file for you to read. 33 * @more 34 * Prefers the real file. If it doesn't exist, uses the temp one, and then copies 35 * it to the real one. If there is both a real file and a temp one, assumes that the 36 * temp one isn't fully written and deletes it. 37 */ chooseForRead()38 public File chooseForRead() { 39 File result; 40 if (mReal.exists()) { 41 result = mReal; 42 if (mTemp.exists()) { 43 mTemp.delete(); 44 } 45 } else if (mTemp.exists()) { 46 result = mTemp; 47 mTemp.renameTo(mReal); 48 } else { 49 return mReal; 50 } 51 return result; 52 } 53 54 /** 55 * Returns a file for you to write. 56 * @more 57 * If a write is already happening, throws. In other words, you must provide your 58 * own locking. 59 * <p> 60 * Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes. 61 */ chooseForWrite()62 public File chooseForWrite() { 63 if (mWriting) { 64 throw new IllegalStateException("uncommitted write already in progress"); 65 } 66 if (!mReal.exists()) { 67 // If the real one doesn't exist, it's either because this is the first time 68 // or because something went wrong while copying them. In this case, we can't 69 // trust anything that's in temp. In order to have the chooseForRead code not 70 // use the temporary one until it's fully written, create an empty file 71 // for real, which will we'll shortly delete. 72 try { 73 mReal.createNewFile(); 74 } catch (IOException e) { 75 // Ignore 76 } 77 } 78 79 if (mTemp.exists()) { 80 mTemp.delete(); 81 } 82 mWriting = true; 83 return mTemp; 84 } 85 86 /** 87 * Commit changes. 88 */ commit()89 public void commit() { 90 if (!mWriting) { 91 throw new IllegalStateException("no file to commit"); 92 } 93 mWriting = false; 94 mTemp.renameTo(mReal); 95 } 96 97 /** 98 * Roll back changes. 99 */ rollback()100 public void rollback() { 101 if (!mWriting) { 102 throw new IllegalStateException("no file to roll back"); 103 } 104 mWriting = false; 105 mTemp.delete(); 106 } 107 } 108