1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.transport;
12
13 import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
14 import static org.eclipse.jgit.util.StringUtils.toLowerCase;
15
16 import java.io.File;
17 import java.util.EnumSet;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.eclipse.jgit.annotations.Nullable;
22 import org.eclipse.jgit.internal.storage.file.LazyObjectIdSetFile;
23 import org.eclipse.jgit.lib.Config;
24 import org.eclipse.jgit.lib.ConfigConstants;
25 import org.eclipse.jgit.lib.Config.SectionParser;
26 import org.eclipse.jgit.lib.ObjectChecker;
27 import org.eclipse.jgit.lib.ObjectIdSet;
28 import org.eclipse.jgit.lib.Ref;
29 import org.eclipse.jgit.lib.Repository;
30 import org.eclipse.jgit.util.SystemReader;
31
32
33
34
35
36 public class TransferConfig {
37 private static final String FSCK = "fsck";
38
39
40 public static final Config.SectionParser<TransferConfig> KEY =
41 TransferConfig::new;
42
43
44
45
46
47
48 public enum FsckMode {
49
50
51
52 ERROR,
53
54
55
56 WARN,
57
58
59
60 IGNORE;
61 }
62
63
64
65
66
67
68
69 public enum ProtocolVersion {
70
71
72
73 V0("0"),
74
75
76
77 V2("2");
78
79 final String name;
80
81 ProtocolVersion(String name) {
82 this.name = name;
83 }
84
85
86
87
88
89
90 public String version() {
91 return name;
92 }
93
94 @Nullable
95 static ProtocolVersion parse(@Nullable String name) {
96 if (name == null) {
97 return null;
98 }
99 for (ProtocolVersion v : ProtocolVersion.values()) {
100 if (v.name.equals(name)) {
101 return v;
102 }
103 }
104 return null;
105 }
106 }
107
108 private final boolean fetchFsck;
109 private final boolean receiveFsck;
110 private final String fsckSkipList;
111 private final EnumSet<ObjectChecker.ErrorType> ignore;
112 private final boolean allowInvalidPersonIdent;
113 private final boolean safeForWindows;
114 private final boolean safeForMacOS;
115 private final boolean allowRefInWant;
116 private final boolean allowTipSha1InWant;
117 private final boolean allowReachableSha1InWant;
118 private final boolean allowFilter;
119 private final boolean allowSidebandAll;
120 private final boolean advertiseSidebandAll;
121 final @Nullable ProtocolVersion protocolVersion;
122 final String[] hideRefs;
123
124
125
126
127
128
129
130
131
132
133 public TransferConfig(Repository db) {
134 this(db.getConfig());
135 }
136
137
138
139
140
141
142
143
144
145
146
147 @SuppressWarnings("nls")
148 public TransferConfig(Config rc) {
149 boolean fsck = rc.getBoolean("transfer", "fsckobjects", false);
150 fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck);
151 receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck);
152 fsckSkipList = rc.getString(FSCK, null, "skipList");
153 allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent",
154 false);
155 safeForWindows = rc.getBoolean(FSCK, "safeForWindows",
156 SystemReader.getInstance().isWindows());
157 safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS",
158 SystemReader.getInstance().isMacOS());
159
160 ignore = EnumSet.noneOf(ObjectChecker.ErrorType.class);
161 EnumSet<ObjectChecker.ErrorType> set = EnumSet
162 .noneOf(ObjectChecker.ErrorType.class);
163 for (String key : rc.getNames(FSCK)) {
164 if (equalsIgnoreCase(key, "skipList")
165 || equalsIgnoreCase(key, "allowLeadingZeroFileMode")
166 || equalsIgnoreCase(key, "allowInvalidPersonIdent")
167 || equalsIgnoreCase(key, "safeForWindows")
168 || equalsIgnoreCase(key, "safeForMacOS")) {
169 continue;
170 }
171
172 ObjectChecker.ErrorType id = FsckKeyNameHolder.parse(key);
173 if (id != null) {
174 switch (rc.getEnum(FSCK, null, key, FsckMode.ERROR)) {
175 case ERROR:
176 ignore.remove(id);
177 break;
178 case WARN:
179 case IGNORE:
180 ignore.add(id);
181 break;
182 }
183 set.add(id);
184 }
185 }
186 if (!set.contains(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE)
187 && rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) {
188 ignore.add(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE);
189 }
190
191 allowRefInWant = rc.getBoolean("uploadpack", "allowrefinwant", false);
192 allowTipSha1InWant = rc.getBoolean(
193 "uploadpack", "allowtipsha1inwant", false);
194 allowReachableSha1InWant = rc.getBoolean(
195 "uploadpack", "allowreachablesha1inwant", false);
196 allowFilter = rc.getBoolean(
197 "uploadpack", "allowfilter", false);
198 protocolVersion = ProtocolVersion.parse(rc
199 .getString(ConfigConstants.CONFIG_PROTOCOL_SECTION, null,
200 ConfigConstants.CONFIG_KEY_VERSION));
201 hideRefs = rc.getStringList("uploadpack", null, "hiderefs");
202 allowSidebandAll = rc.getBoolean(
203 "uploadpack", "allowsidebandall", false);
204 advertiseSidebandAll = rc.getBoolean("uploadpack",
205 "advertisesidebandall", false);
206 }
207
208
209
210
211
212
213
214
215 @Nullable
216 public ObjectChecker newObjectChecker() {
217 return newObjectChecker(fetchFsck);
218 }
219
220
221
222
223
224
225
226
227 @Nullable
228 public ObjectChecker newReceiveObjectChecker() {
229 return newObjectChecker(receiveFsck);
230 }
231
232 private ObjectChecker newObjectChecker(boolean check) {
233 if (!check) {
234 return null;
235 }
236 return new ObjectChecker()
237 .setIgnore(ignore)
238 .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
239 .setSafeForWindows(safeForWindows)
240 .setSafeForMacOS(safeForMacOS)
241 .setSkipList(skipList());
242 }
243
244 private ObjectIdSet skipList() {
245 if (fsckSkipList != null && !fsckSkipList.isEmpty()) {
246 return new LazyObjectIdSetFile(new File(fsckSkipList));
247 }
248 return null;
249 }
250
251
252
253
254
255
256
257 public boolean isAllowTipSha1InWant() {
258 return allowTipSha1InWant;
259 }
260
261
262
263
264
265
266
267 public boolean isAllowReachableSha1InWant() {
268 return allowReachableSha1InWant;
269 }
270
271
272
273
274
275 public boolean isAllowFilter() {
276 return allowFilter;
277 }
278
279
280
281
282
283 public boolean isAllowRefInWant() {
284 return allowRefInWant;
285 }
286
287
288
289
290
291
292 public boolean isAllowSidebandAll() {
293 return allowSidebandAll;
294 }
295
296
297
298
299
300 public boolean isAdvertiseSidebandAll() {
301 return advertiseSidebandAll && allowSidebandAll;
302 }
303
304
305
306
307
308
309
310
311
312 public RefFilter getRefFilter() {
313 if (hideRefs.length == 0)
314 return RefFilter.DEFAULT;
315
316 return new RefFilter() {
317 @Override
318 public Map<String, Ref> filter(Map<String, Ref> refs) {
319 Map<String, Ref> result = new HashMap<>();
320 for (Map.Entry<String, Ref> e : refs.entrySet()) {
321 boolean add = true;
322 for (String hide : hideRefs) {
323 if (e.getKey().equals(hide) || prefixMatch(hide, e.getKey())) {
324 add = false;
325 break;
326 }
327 }
328 if (add)
329 result.put(e.getKey(), e.getValue());
330 }
331 return result;
332 }
333
334 private boolean prefixMatch(String p, String s) {
335 return p.charAt(p.length() - 1) == '/' && s.startsWith(p);
336 }
337 };
338 }
339
340
341
342
343
344
345
346 boolean hasDefaultRefFilter() {
347 return hideRefs.length == 0;
348 }
349
350 static class FsckKeyNameHolder {
351 private static final Map<String, ObjectChecker.ErrorType> errors;
352
353 static {
354 errors = new HashMap<>();
355 for (ObjectChecker.ErrorType m : ObjectChecker.ErrorType.values()) {
356 errors.put(keyNameFor(m.name()), m);
357 }
358 }
359
360 @Nullable
361 static ObjectChecker.ErrorType parse(String key) {
362 return errors.get(toLowerCase(key));
363 }
364
365 private static String keyNameFor(String name) {
366 StringBuilder r = new StringBuilder(name.length());
367 for (int i = 0; i < name.length(); i++) {
368 char c = name.charAt(i);
369 if (c != '_') {
370 r.append(c);
371 }
372 }
373 return toLowerCase(r.toString());
374 }
375
376 private FsckKeyNameHolder() {
377 }
378 }
379 }