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 if ("1".equals(name)) {
105 return V0;
106 }
107 return null;
108 }
109 }
110
111 private final boolean fetchFsck;
112 private final boolean receiveFsck;
113 private final String fsckSkipList;
114 private final EnumSet<ObjectChecker.ErrorType> ignore;
115 private final boolean allowInvalidPersonIdent;
116 private final boolean safeForWindows;
117 private final boolean safeForMacOS;
118 private final boolean allowRefInWant;
119 private final boolean allowTipSha1InWant;
120 private final boolean allowReachableSha1InWant;
121 private final boolean allowFilter;
122 private final boolean allowSidebandAll;
123 private final boolean advertiseSidebandAll;
124 final @Nullable ProtocolVersion protocolVersion;
125 final String[] hideRefs;
126
127
128
129
130
131
132
133
134
135
136 public TransferConfig(Repository db) {
137 this(db.getConfig());
138 }
139
140
141
142
143
144
145
146
147
148
149
150 @SuppressWarnings("nls")
151 public TransferConfig(Config rc) {
152 boolean fsck = rc.getBoolean("transfer", "fsckobjects", false);
153 fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck);
154 receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck);
155 fsckSkipList = rc.getString(FSCK, null, "skipList");
156 allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent",
157 false);
158 safeForWindows = rc.getBoolean(FSCK, "safeForWindows",
159 SystemReader.getInstance().isWindows());
160 safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS",
161 SystemReader.getInstance().isMacOS());
162
163 ignore = EnumSet.noneOf(ObjectChecker.ErrorType.class);
164 EnumSet<ObjectChecker.ErrorType> set = EnumSet
165 .noneOf(ObjectChecker.ErrorType.class);
166 for (String key : rc.getNames(FSCK)) {
167 if (equalsIgnoreCase(key, "skipList")
168 || equalsIgnoreCase(key, "allowLeadingZeroFileMode")
169 || equalsIgnoreCase(key, "allowInvalidPersonIdent")
170 || equalsIgnoreCase(key, "safeForWindows")
171 || equalsIgnoreCase(key, "safeForMacOS")) {
172 continue;
173 }
174
175 ObjectChecker.ErrorType id = FsckKeyNameHolder.parse(key);
176 if (id != null) {
177 switch (rc.getEnum(FSCK, null, key, FsckMode.ERROR)) {
178 case ERROR:
179 ignore.remove(id);
180 break;
181 case WARN:
182 case IGNORE:
183 ignore.add(id);
184 break;
185 }
186 set.add(id);
187 }
188 }
189 if (!set.contains(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE)
190 && rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) {
191 ignore.add(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE);
192 }
193
194 allowRefInWant = rc.getBoolean("uploadpack", "allowrefinwant", false);
195 allowTipSha1InWant = rc.getBoolean(
196 "uploadpack", "allowtipsha1inwant", false);
197 allowReachableSha1InWant = rc.getBoolean(
198 "uploadpack", "allowreachablesha1inwant", false);
199 allowFilter = rc.getBoolean(
200 "uploadpack", "allowfilter", false);
201 protocolVersion = ProtocolVersion.parse(rc
202 .getString(ConfigConstants.CONFIG_PROTOCOL_SECTION, null,
203 ConfigConstants.CONFIG_KEY_VERSION));
204 hideRefs = rc.getStringList("uploadpack", null, "hiderefs");
205 allowSidebandAll = rc.getBoolean(
206 "uploadpack", "allowsidebandall", false);
207 advertiseSidebandAll = rc.getBoolean("uploadpack",
208 "advertisesidebandall", false);
209 }
210
211
212
213
214
215
216
217
218 @Nullable
219 public ObjectChecker newObjectChecker() {
220 return newObjectChecker(fetchFsck);
221 }
222
223
224
225
226
227
228
229
230 @Nullable
231 public ObjectChecker newReceiveObjectChecker() {
232 return newObjectChecker(receiveFsck);
233 }
234
235 private ObjectChecker newObjectChecker(boolean check) {
236 if (!check) {
237 return null;
238 }
239 return new ObjectChecker()
240 .setIgnore(ignore)
241 .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
242 .setSafeForWindows(safeForWindows)
243 .setSafeForMacOS(safeForMacOS)
244 .setSkipList(skipList());
245 }
246
247 private ObjectIdSet skipList() {
248 if (fsckSkipList != null && !fsckSkipList.isEmpty()) {
249 return new LazyObjectIdSetFile(new File(fsckSkipList));
250 }
251 return null;
252 }
253
254
255
256
257
258
259
260 public boolean isAllowTipSha1InWant() {
261 return allowTipSha1InWant;
262 }
263
264
265
266
267
268
269
270 public boolean isAllowReachableSha1InWant() {
271 return allowReachableSha1InWant;
272 }
273
274
275
276
277
278 public boolean isAllowFilter() {
279 return allowFilter;
280 }
281
282
283
284
285
286 public boolean isAllowRefInWant() {
287 return allowRefInWant;
288 }
289
290
291
292
293
294
295 public boolean isAllowSidebandAll() {
296 return allowSidebandAll;
297 }
298
299
300
301
302
303 public boolean isAdvertiseSidebandAll() {
304 return advertiseSidebandAll && allowSidebandAll;
305 }
306
307
308
309
310
311
312
313
314
315 public RefFilter getRefFilter() {
316 if (hideRefs.length == 0)
317 return RefFilter.DEFAULT;
318
319 return new RefFilter() {
320 @Override
321 public Map<String, Ref> filter(Map<String, Ref> refs) {
322 Map<String, Ref> result = new HashMap<>();
323 for (Map.Entry<String, Ref> e : refs.entrySet()) {
324 boolean add = true;
325 for (String hide : hideRefs) {
326 if (e.getKey().equals(hide) || prefixMatch(hide, e.getKey())) {
327 add = false;
328 break;
329 }
330 }
331 if (add)
332 result.put(e.getKey(), e.getValue());
333 }
334 return result;
335 }
336
337 private boolean prefixMatch(String p, String s) {
338 return p.charAt(p.length() - 1) == '/' && s.startsWith(p);
339 }
340 };
341 }
342
343
344
345
346
347
348
349 boolean hasDefaultRefFilter() {
350 return hideRefs.length == 0;
351 }
352
353 static class FsckKeyNameHolder {
354 private static final Map<String, ObjectChecker.ErrorType> errors;
355
356 static {
357 errors = new HashMap<>();
358 for (ObjectChecker.ErrorType m : ObjectChecker.ErrorType.values()) {
359 errors.put(keyNameFor(m.name()), m);
360 }
361 }
362
363 @Nullable
364 static ObjectChecker.ErrorType parse(String key) {
365 return errors.get(toLowerCase(key));
366 }
367
368 private static String keyNameFor(String name) {
369 StringBuilder r = new StringBuilder(name.length());
370 for (int i = 0; i < name.length(); i++) {
371 char c = name.charAt(i);
372 if (c != '_') {
373 r.append(c);
374 }
375 }
376 return toLowerCase(r.toString());
377 }
378
379 private FsckKeyNameHolder() {
380 }
381 }
382 }