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 package org.eclipse.jgit.internal.storage.dfs;
45
46 import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
47 import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
48
49 import java.io.FileNotFoundException;
50 import java.io.IOException;
51
52 import org.eclipse.jgit.errors.CorruptPackIndexException;
53 import org.eclipse.jgit.errors.MissingObjectException;
54 import org.eclipse.jgit.internal.JGitText;
55 import org.eclipse.jgit.internal.fsck.FsckError;
56 import org.eclipse.jgit.internal.fsck.FsckError.CorruptIndex;
57 import org.eclipse.jgit.internal.fsck.FsckPackParser;
58 import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
59 import org.eclipse.jgit.lib.Constants;
60 import org.eclipse.jgit.lib.NullProgressMonitor;
61 import org.eclipse.jgit.lib.ObjectChecker;
62 import org.eclipse.jgit.lib.ObjectId;
63 import org.eclipse.jgit.lib.ProgressMonitor;
64 import org.eclipse.jgit.lib.Ref;
65 import org.eclipse.jgit.revwalk.ObjectWalk;
66 import org.eclipse.jgit.revwalk.RevObject;
67
68
69
70
71 public class DfsFsck {
72 private final DfsRepository repo;
73 private final DfsObjDatabase objdb;
74 private ObjectChecker objChecker = new ObjectChecker();
75 private boolean connectivityOnly;
76
77
78
79
80
81
82
83 public DfsFsck(DfsRepository repository) {
84 repo = repository;
85 objdb = repo.getObjectDatabase();
86 }
87
88
89
90
91
92
93
94
95
96
97
98 public FsckError check(ProgressMonitor pm) throws IOException {
99 if (pm == null) {
100 pm = NullProgressMonitor.INSTANCE;
101 }
102
103 FsckError errors = new FsckError();
104 if (!connectivityOnly) {
105 checkPacks(pm, errors);
106 }
107 checkConnectivity(pm, errors);
108 return errors;
109 }
110
111 private void checkPacks(ProgressMonitor pm, FsckError errors)
112 throws IOException, FileNotFoundException {
113 try (DfsReader ctx = objdb.newReader()) {
114 for (DfsPackFile pack : objdb.getPacks()) {
115 DfsPackDescription packDesc = pack.getPackDescription();
116 if (packDesc.getPackSource()
117 == PackSource.UNREACHABLE_GARBAGE) {
118 continue;
119 }
120 try (ReadableChannel rc = objdb.openFile(packDesc, PACK)) {
121 verifyPack(pm, errors, ctx, pack, rc);
122 } catch (MissingObjectException e) {
123 errors.getMissingObjects().add(e.getObjectId());
124 } catch (CorruptPackIndexException e) {
125 errors.getCorruptIndices().add(new CorruptIndex(
126 pack.getPackDescription().getFileName(INDEX),
127 e.getErrorType()));
128 }
129 }
130 }
131 }
132
133 private void verifyPack(ProgressMonitor pm, FsckError errors, DfsReader ctx,
134 DfsPackFile pack, ReadableChannel ch)
135 throws IOException, CorruptPackIndexException {
136 FsckPackParser fpp = new FsckPackParser(objdb, ch);
137 fpp.setObjectChecker(objChecker);
138 fpp.overwriteObjectCount(pack.getPackDescription().getObjectCount());
139 fpp.parse(pm);
140 errors.getCorruptObjects().addAll(fpp.getCorruptObjects());
141
142 fpp.verifyIndex(pack.getPackIndex(ctx));
143 }
144
145 private void checkConnectivity(ProgressMonitor pm, FsckError errors)
146 throws IOException {
147 pm.beginTask(JGitText.get().countingObjects, ProgressMonitor.UNKNOWN);
148 try (ObjectWalk ow = new ObjectWalk(repo)) {
149 for (Ref r : repo.getRefDatabase().getRefs()) {
150 ObjectId objectId = r.getObjectId();
151 if (objectId == null) {
152
153 continue;
154 }
155 RevObject tip;
156 try {
157 tip = ow.parseAny(objectId);
158 if (r.getLeaf().getName().startsWith(Constants.R_HEADS)
159 && tip.getType() != Constants.OBJ_COMMIT) {
160
161 errors.getNonCommitHeads().add(r.getLeaf().getName());
162 }
163 ow.markStart(tip);
164 } catch (MissingObjectException e) {
165 errors.getMissingObjects().add(e.getObjectId());
166 continue;
167 }
168 }
169 try {
170 ow.checkConnectivity();
171 } catch (MissingObjectException e) {
172 errors.getMissingObjects().add(e.getObjectId());
173 }
174 }
175 pm.endTask();
176 }
177
178
179
180
181
182
183
184
185 public void setObjectChecker(ObjectChecker objChecker) {
186 this.objChecker = objChecker;
187 }
188
189
190
191
192
193
194
195
196
197
198 public void setConnectivityOnly(boolean connectivityOnly) {
199 this.connectivityOnly = connectivityOnly;
200 }
201 }