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 clear();
167 snapshot = newSnapshot;
168 } catch (IOException e) {
169 final IOException e2 = new IOException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()));
170 e2.initCause(e);
171 throw e2;
172 } catch (ConfigInvalidException e) {
173 throw new ConfigInvalidException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()), e);
174 }
175 }
176
177
178
179
180
181
182
183
184
185
186
187
188
189 public void save() throws IOException {
190 final byte[] out;
191 final String text = toText();
192 if (utf8Bom) {
193 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
194 bos.write(0xEF);
195 bos.write(0xBB);
196 bos.write(0xBF);
197 bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET.name()));
198 out = bos.toByteArray();
199 } else {
200 out = Constants.encode(text);
201 }
202
203 final LockFile lf = new LockFile(getFile(), fs);
204 if (!lf.lock())
205 throw new LockFailedException(getFile());
206 try {
207 lf.setNeedSnapshot(true);
208 lf.write(out);
209 if (!lf.commit())
210 throw new IOException(MessageFormat.format(JGitText.get().cannotCommitWriteTo, getFile()));
211 } finally {
212 lf.unlock();
213 }
214 snapshot = lf.getCommitSnapshot();
215 hash = hash(out);
216
217 fireConfigChangedEvent();
218 }
219
220 @Override
221 public void clear() {
222 hash = hash(new byte[0]);
223 super.clear();
224 }
225
226 private static ObjectId hash(final byte[] rawText) {
227 return ObjectId.fromRaw(Constants.newMessageDigest().digest(rawText));
228 }
229
230 @SuppressWarnings("nls")
231 @Override
232 public String toString() {
233 return getClass().getSimpleName() + "[" + getFile().getPath() + "]";
234 }
235
236
237
238
239
240 public boolean isOutdated() {
241 return snapshot.isModified(getFile());
242 }
243 }