Home | History | Annotate | Download | only in util
      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.internal.util;
     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 
     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      */
     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      */
     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      */
     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      */
    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