1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 package org.eclipse.jgit.storage.file;
51
52 import java.io.ByteArrayOutputStream;
53 import java.io.File;
54 import java.io.FileNotFoundException;
55 import java.io.IOException;
56 import java.text.MessageFormat;
57
58 import org.eclipse.jgit.errors.LockFailedException;
59 import org.eclipse.jgit.errors.ConfigInvalidException;
60 import org.eclipse.jgit.internal.JGitText;
61 import org.eclipse.jgit.internal.storage.file.FileSnapshot;
62 import org.eclipse.jgit.internal.storage.file.LockFile;
63 import org.eclipse.jgit.lib.Config;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.ObjectId;
66 import org.eclipse.jgit.lib.StoredConfig;
67 import org.eclipse.jgit.util.FS;
68 import org.eclipse.jgit.util.IO;
69 import org.eclipse.jgit.util.RawParseUtils;
70
71
72
73
74 public class FileBasedConfig extends StoredConfig {
75 private final File configFile;
76
77 private final FS fs;
78
79 private boolean utf8Bom;
80
81 private volatile FileSnapshot snapshot;
82
83 private volatile ObjectId hash;
84
85
86
87
88
89
90
91
92
93
94 public FileBasedConfig(File cfgLocation, FS fs) {
95 this(null, cfgLocation, fs);
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109 public FileBasedConfig(Config base, File cfgLocation, FS fs) {
110 super(base);
111 configFile = cfgLocation;
112 this.fs = fs;
113 this.snapshot = FileSnapshot.DIRTY;
114 this.hash = ObjectId.zeroId();
115 }
116
117 @Override
118 protected boolean notifyUponTransientChanges() {
119
120 return false;
121 }
122
123
124 public final File getFile() {
125 return configFile;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139 @Override
140 public void load() throws IOException, ConfigInvalidException {
141 final FileSnapshot oldSnapshot = snapshot;
142 final FileSnapshot newSnapshot = FileSnapshot.save(getFile());
143 try {
144 final byte[] in = IO.readFully(getFile());
145 final ObjectId newHash = hash(in);
146 if (hash.equals(newHash)) {
147 if (oldSnapshot.equals(newSnapshot))
148 oldSnapshot.setClean(newSnapshot);
149 else
150 snapshot = newSnapshot;
151 } else {
152 final String decoded;
153 if (in.length >= 3 && in[0] == (byte) 0xEF
154 && in[1] == (byte) 0xBB && in[2] == (byte) 0xBF) {
155 decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
156 in, 3, in.length);
157 utf8Bom = true;
158 } else {
159 decoded = RawParseUtils.decode(in);
160 }
161 fromText(decoded);
162 snapshot = newSnapshot;
163 hash = newHash;
164 }
165 } catch (FileNotFoundException noFile) {
166 if (configFile.exists()) {
167 throw noFile;
168 }
169 clear();
170 snapshot = newSnapshot;
171 } catch (IOException e) {
172 final IOException e2 = new IOException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()));
173 e2.initCause(e);
174 throw e2;
175 } catch (ConfigInvalidException e) {
176 throw new ConfigInvalidException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()), e);
177 }
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192 public void save() throws IOException {
193 final byte[] out;
194 final String text = toText();
195 if (utf8Bom) {
196 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
197 bos.write(0xEF);
198 bos.write(0xBB);
199 bos.write(0xBF);
200 bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET.name()));
201 out = bos.toByteArray();
202 } else {
203 out = Constants.encode(text);
204 }
205
206 final LockFile lf = new LockFile(getFile(), fs);
207 if (!lf.lock())
208 throw new LockFailedException(getFile());
209 try {
210 lf.setNeedSnapshot(true);
211 lf.write(out);
212 if (!lf.commit())
213 throw new IOException(MessageFormat.format(JGitText.get().cannotCommitWriteTo, getFile()));
214 } finally {
215 lf.unlock();
216 }
217 snapshot = lf.getCommitSnapshot();
218 hash = hash(out);
219
220 fireConfigChangedEvent();
221 }
222
223 @Override
224 public void clear() {
225 hash = hash(new byte[0]);
226 super.clear();
227 }
228
229 private static ObjectId hash(final byte[] rawText) {
230 return ObjectId.fromRaw(Constants.newMessageDigest().digest(rawText));
231 }
232
233 @SuppressWarnings("nls")
234 @Override
235 public String toString() {
236 return getClass().getSimpleName() + "[" + getFile().getPath() + "]";
237 }
238
239
240
241
242
243 public boolean isOutdated() {
244 return snapshot.isModified(getFile());
245 }
246 }