blob: 3d1f52db34b3e76496b3b1f2dfb9d671bab9cefb [file] [log] [blame]
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001/*
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
17package com.android.server;
18
19import java.io.File;
20import java.io.IOException;
21
22public 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}