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 package org.eclipse.jgit.transport;
46
47 import static org.eclipse.jgit.lib.RefDatabase.ALL;
48
49 import java.io.File;
50 import java.io.FileNotFoundException;
51 import java.io.FileOutputStream;
52 import java.io.IOException;
53 import java.text.MessageFormat;
54 import java.util.ArrayList;
55 import java.util.Collection;
56 import java.util.HashMap;
57 import java.util.HashSet;
58 import java.util.Iterator;
59 import java.util.LinkedList;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.Set;
63
64 import org.eclipse.jgit.errors.CompoundException;
65 import org.eclipse.jgit.errors.CorruptObjectException;
66 import org.eclipse.jgit.errors.MissingObjectException;
67 import org.eclipse.jgit.errors.TransportException;
68 import org.eclipse.jgit.internal.JGitText;
69 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
70 import org.eclipse.jgit.internal.storage.file.PackIndex;
71 import org.eclipse.jgit.internal.storage.file.PackLock;
72 import org.eclipse.jgit.internal.storage.file.UnpackedObject;
73 import org.eclipse.jgit.lib.AnyObjectId;
74 import org.eclipse.jgit.lib.Constants;
75 import org.eclipse.jgit.lib.FileMode;
76 import org.eclipse.jgit.lib.MutableObjectId;
77 import org.eclipse.jgit.lib.ObjectChecker;
78 import org.eclipse.jgit.lib.ObjectId;
79 import org.eclipse.jgit.lib.ObjectInserter;
80 import org.eclipse.jgit.lib.ObjectLoader;
81 import org.eclipse.jgit.lib.ObjectReader;
82 import org.eclipse.jgit.lib.ProgressMonitor;
83 import org.eclipse.jgit.lib.Ref;
84 import org.eclipse.jgit.lib.Repository;
85 import org.eclipse.jgit.revwalk.DateRevQueue;
86 import org.eclipse.jgit.revwalk.RevCommit;
87 import org.eclipse.jgit.revwalk.RevFlag;
88 import org.eclipse.jgit.revwalk.RevObject;
89 import org.eclipse.jgit.revwalk.RevTag;
90 import org.eclipse.jgit.revwalk.RevTree;
91 import org.eclipse.jgit.revwalk.RevWalk;
92 import org.eclipse.jgit.treewalk.TreeWalk;
93 import org.eclipse.jgit.util.FileUtils;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 class WalkFetchConnection extends BaseFetchConnection {
117
118 final Repository local;
119
120
121 final ObjectChecker objCheck;
122
123
124
125
126
127
128
129
130 private final List<WalkRemoteObjectDatabase> remotes;
131
132
133 private int lastRemoteIdx;
134
135 private final RevWalk revWalk;
136
137 private final TreeWalk treeWalk;
138
139
140 private final RevFlag COMPLETE;
141
142
143 private final RevFlag IN_WORK_QUEUE;
144
145
146 private final RevFlag LOCALLY_SEEN;
147
148
149 private final DateRevQueue localCommitQueue;
150
151
152 private LinkedList<ObjectId> workQueue;
153
154
155 private final LinkedList<WalkRemoteObjectDatabase> noPacksYet;
156
157
158 private final LinkedList<WalkRemoteObjectDatabase> noAlternatesYet;
159
160
161 private final LinkedList<RemotePack> unfetchedPacks;
162
163
164
165
166
167
168
169
170 private final Set<String> packsConsidered;
171
172 private final MutableObjectId idBuffer = new MutableObjectId();
173
174
175
176
177
178
179
180
181 private final HashMap<ObjectId, List<Throwable>> fetchErrors;
182
183 String lockMessage;
184
185 final List<PackLock> packLocks;
186
187
188 final ObjectInserter inserter;
189
190
191 private final ObjectReader reader;
192
193 WalkFetchConnection(final WalkTransport t, final WalkRemoteObjectDatabase w) {
194 Transport wt = (Transport)t;
195 local = wt.local;
196 objCheck = wt.getObjectChecker();
197 inserter = local.newObjectInserter();
198 reader = inserter.newReader();
199
200 remotes = new ArrayList<WalkRemoteObjectDatabase>();
201 remotes.add(w);
202
203 unfetchedPacks = new LinkedList<RemotePack>();
204 packsConsidered = new HashSet<String>();
205
206 noPacksYet = new LinkedList<WalkRemoteObjectDatabase>();
207 noPacksYet.add(w);
208
209 noAlternatesYet = new LinkedList<WalkRemoteObjectDatabase>();
210 noAlternatesYet.add(w);
211
212 fetchErrors = new HashMap<ObjectId, List<Throwable>>();
213 packLocks = new ArrayList<PackLock>(4);
214
215 revWalk = new RevWalk(reader);
216 revWalk.setRetainBody(false);
217 treeWalk = new TreeWalk(reader);
218 COMPLETE = revWalk.newFlag("COMPLETE");
219 IN_WORK_QUEUE = revWalk.newFlag("IN_WORK_QUEUE");
220 LOCALLY_SEEN = revWalk.newFlag("LOCALLY_SEEN");
221
222 localCommitQueue = new DateRevQueue();
223 workQueue = new LinkedList<ObjectId>();
224 }
225
226 public boolean didFetchTestConnectivity() {
227 return true;
228 }
229
230 @Override
231 protected void doFetch(final ProgressMonitor monitor,
232 final Collection<Ref> want, final Set<ObjectId> have)
233 throws TransportException {
234 markLocalRefsComplete(have);
235 queueWants(want);
236
237 while (!monitor.isCancelled() && !workQueue.isEmpty()) {
238 final ObjectId id = workQueue.removeFirst();
239 if (!(id instanceof RevObject) || !((RevObject) id).has(COMPLETE))
240 downloadObject(monitor, id);
241 process(id);
242 }
243
244 try {
245 inserter.flush();
246 } catch (IOException e) {
247 throw new TransportException(e.getMessage(), e);
248 }
249 }
250
251 public Collection<PackLock> getPackLocks() {
252 return packLocks;
253 }
254
255 public void setPackLockMessage(final String message) {
256 lockMessage = message;
257 }
258
259 @Override
260 public void close() {
261 inserter.close();
262 reader.close();
263 for (final RemotePack p : unfetchedPacks) {
264 if (p.tmpIdx != null)
265 p.tmpIdx.delete();
266 }
267 for (final WalkRemoteObjectDatabase r : remotes)
268 r.close();
269 }
270
271 private void queueWants(final Collection<Ref> want)
272 throws TransportException {
273 final HashSet<ObjectId> inWorkQueue = new HashSet<ObjectId>();
274 for (final Ref r : want) {
275 final ObjectId id = r.getObjectId();
276 if (id == null) {
277 throw new NullPointerException(MessageFormat.format(
278 JGitText.get().transportProvidedRefWithNoObjectId, r.getName()));
279 }
280 try {
281 final RevObject obj = revWalk.parseAny(id);
282 if (obj.has(COMPLETE))
283 continue;
284 if (inWorkQueue.add(id)) {
285 obj.add(IN_WORK_QUEUE);
286 workQueue.add(obj);
287 }
288 } catch (MissingObjectException e) {
289 if (inWorkQueue.add(id))
290 workQueue.add(id);
291 } catch (IOException e) {
292 throw new TransportException(MessageFormat.format(JGitText.get().cannotRead, id.name()), e);
293 }
294 }
295 }
296
297 private void process(final ObjectId id) throws TransportException {
298 final RevObject obj;
299 try {
300 if (id instanceof RevObject) {
301 obj = (RevObject) id;
302 if (obj.has(COMPLETE))
303 return;
304 revWalk.parseHeaders(obj);
305 } else {
306 obj = revWalk.parseAny(id);
307 if (obj.has(COMPLETE))
308 return;
309 }
310 } catch (IOException e) {
311 throw new TransportException(MessageFormat.format(JGitText.get().cannotRead, id.name()), e);
312 }
313
314 switch (obj.getType()) {
315 case Constants.OBJ_BLOB:
316 processBlob(obj);
317 break;
318 case Constants.OBJ_TREE:
319 processTree(obj);
320 break;
321 case Constants.OBJ_COMMIT:
322 processCommit(obj);
323 break;
324 case Constants.OBJ_TAG:
325 processTag(obj);
326 break;
327 default:
328 throw new TransportException(MessageFormat.format(JGitText.get().unknownObjectType, id.name()));
329 }
330
331
332
333
334 fetchErrors.remove(id);
335 }
336
337 private void processBlob(final RevObject obj) throws TransportException {
338 try {
339 if (reader.has(obj, Constants.OBJ_BLOB))
340 obj.add(COMPLETE);
341 else
342 throw new TransportException(MessageFormat.format(JGitText
343 .get().cannotReadBlob, obj.name()),
344 new MissingObjectException(obj, Constants.TYPE_BLOB));
345 } catch (IOException error) {
346 throw new TransportException(MessageFormat.format(
347 JGitText.get().cannotReadBlob, obj.name()), error);
348 }
349 }
350
351 private void processTree(final RevObject obj) throws TransportException {
352 try {
353 treeWalk.reset(obj);
354 while (treeWalk.next()) {
355 final FileMode mode = treeWalk.getFileMode(0);
356 final int sType = mode.getObjectType();
357
358 switch (sType) {
359 case Constants.OBJ_BLOB:
360 case Constants.OBJ_TREE:
361 treeWalk.getObjectId(idBuffer, 0);
362 needs(revWalk.lookupAny(idBuffer, sType));
363 continue;
364
365 default:
366 if (FileMode.GITLINK.equals(mode))
367 continue;
368 treeWalk.getObjectId(idBuffer, 0);
369 throw new CorruptObjectException(MessageFormat.format(JGitText.get().invalidModeFor
370 , mode, idBuffer.name(), treeWalk.getPathString(), obj.getId().name()));
371 }
372 }
373 } catch (IOException ioe) {
374 throw new TransportException(MessageFormat.format(JGitText.get().cannotReadTree, obj.name()), ioe);
375 }
376 obj.add(COMPLETE);
377 }
378
379 private void processCommit(final RevObject obj) throws TransportException {
380 final RevCommit commit = (RevCommit) obj;
381 markLocalCommitsComplete(commit.getCommitTime());
382 needs(commit.getTree());
383 for (final RevCommit p : commit.getParents())
384 needs(p);
385 obj.add(COMPLETE);
386 }
387
388 private void processTag(final RevObject obj) {
389 final RevTag tag = (RevTag) obj;
390 needs(tag.getObject());
391 obj.add(COMPLETE);
392 }
393
394 private void needs(final RevObject obj) {
395 if (obj.has(COMPLETE))
396 return;
397 if (!obj.has(IN_WORK_QUEUE)) {
398 obj.add(IN_WORK_QUEUE);
399 workQueue.add(obj);
400 }
401 }
402
403 private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
404 throws TransportException {
405 if (alreadyHave(id))
406 return;
407
408 for (;;) {
409
410
411
412
413 if (downloadPackedObject(pm, id))
414 return;
415
416
417
418
419 final String idStr = id.name();
420 final String subdir = idStr.substring(0, 2);
421 final String file = idStr.substring(2);
422 final String looseName = subdir + "/" + file;
423
424 for (int i = lastRemoteIdx; i < remotes.size(); i++) {
425 if (downloadLooseObject(id, looseName, remotes.get(i))) {
426 lastRemoteIdx = i;
427 return;
428 }
429 }
430 for (int i = 0; i < lastRemoteIdx; i++) {
431 if (downloadLooseObject(id, looseName, remotes.get(i))) {
432 lastRemoteIdx = i;
433 return;
434 }
435 }
436
437
438
439 while (!noPacksYet.isEmpty()) {
440 final WalkRemoteObjectDatabase wrr = noPacksYet.removeFirst();
441 final Collection<String> packNameList;
442 try {
443 pm.beginTask(JGitText.get().listingPacks,
444 ProgressMonitor.UNKNOWN);
445 packNameList = wrr.getPackNames();
446 } catch (IOException e) {
447
448
449 recordError(id, e);
450 continue;
451 } finally {
452 pm.endTask();
453 }
454
455 if (packNameList == null || packNameList.isEmpty())
456 continue;
457 for (final String packName : packNameList) {
458 if (packsConsidered.add(packName))
459 unfetchedPacks.add(new RemotePack(wrr, packName));
460 }
461 if (downloadPackedObject(pm, id))
462 return;
463 }
464
465
466
467 Collection<WalkRemoteObjectDatabase> al = expandOneAlternate(id, pm);
468 if (al != null && !al.isEmpty()) {
469 for (final WalkRemoteObjectDatabase alt : al) {
470 remotes.add(alt);
471 noPacksYet.add(alt);
472 noAlternatesYet.add(alt);
473 }
474 continue;
475 }
476
477
478
479 List<Throwable> failures = fetchErrors.get(id);
480 final TransportException te;
481
482 te = new TransportException(MessageFormat.format(JGitText.get().cannotGet, id.name()));
483 if (failures != null && !failures.isEmpty()) {
484 if (failures.size() == 1)
485 te.initCause(failures.get(0));
486 else
487 te.initCause(new CompoundException(failures));
488 }
489 throw te;
490 }
491 }
492
493 private boolean alreadyHave(final AnyObjectId id) throws TransportException {
494 try {
495 return reader.has(id);
496 } catch (IOException error) {
497 throw new TransportException(MessageFormat.format(
498 JGitText.get().cannotReadObject, id.name()), error);
499 }
500 }
501
502 private boolean downloadPackedObject(final ProgressMonitor monitor,
503 final AnyObjectId id) throws TransportException {
504
505
506
507 final Iterator<RemotePack> packItr = unfetchedPacks.iterator();
508 while (packItr.hasNext() && !monitor.isCancelled()) {
509 final RemotePack pack = packItr.next();
510 try {
511 pack.openIndex(monitor);
512 } catch (IOException err) {
513
514
515
516
517
518 recordError(id, err);
519 packItr.remove();
520 continue;
521 }
522
523 if (monitor.isCancelled()) {
524
525
526
527
528 return false;
529 }
530
531 if (!pack.index.hasObject(id)) {
532
533
534 continue;
535 }
536
537
538
539
540
541 try {
542 pack.downloadPack(monitor);
543 } catch (IOException err) {
544
545
546
547
548
549 recordError(id, err);
550 continue;
551 } finally {
552
553
554
555
556
557
558 try {
559 if (pack.tmpIdx != null)
560 FileUtils.delete(pack.tmpIdx);
561 } catch (IOException e) {
562 throw new TransportException(e.getMessage(), e);
563 }
564 packItr.remove();
565 }
566
567 if (!alreadyHave(id)) {
568
569
570
571
572 recordError(id, new FileNotFoundException(MessageFormat.format(
573 JGitText.get().objectNotFoundIn, id.name(), pack.packName)));
574 continue;
575 }
576
577
578
579 final Iterator<ObjectId> pending = swapFetchQueue();
580 while (pending.hasNext()) {
581 final ObjectId p = pending.next();
582 if (pack.index.hasObject(p)) {
583 pending.remove();
584 process(p);
585 } else {
586 workQueue.add(p);
587 }
588 }
589 return true;
590
591 }
592 return false;
593 }
594
595 private Iterator<ObjectId> swapFetchQueue() {
596 final Iterator<ObjectId> r = workQueue.iterator();
597 workQueue = new LinkedList<ObjectId>();
598 return r;
599 }
600
601 private boolean downloadLooseObject(final AnyObjectId id,
602 final String looseName, final WalkRemoteObjectDatabase remote)
603 throws TransportException {
604 try {
605 final byte[] compressed = remote.open(looseName).toArray();
606 verifyAndInsertLooseObject(id, compressed);
607 return true;
608 } catch (FileNotFoundException e) {
609
610
611
612 recordError(id, e);
613 return false;
614 } catch (IOException e) {
615 throw new TransportException(MessageFormat.format(JGitText.get().cannotDownload, id.name()), e);
616 }
617 }
618
619 private void verifyAndInsertLooseObject(final AnyObjectId id,
620 final byte[] compressed) throws IOException {
621 final ObjectLoader uol;
622 try {
623 uol = UnpackedObject.parse(compressed, id);
624 } catch (CorruptObjectException parsingError) {
625
626
627
628
629
630
631
632
633
634
635
636 final FileNotFoundException e;
637 e = new FileNotFoundException(id.name());
638 e.initCause(parsingError);
639 throw e;
640 }
641
642 final int type = uol.getType();
643 final byte[] raw = uol.getCachedBytes();
644 if (objCheck != null) {
645 try {
646 objCheck.check(id, type, raw);
647 } catch (CorruptObjectException e) {
648 throw new TransportException(MessageFormat.format(
649 JGitText.get().transportExceptionInvalid,
650 Constants.typeString(type), id.name(), e.getMessage()));
651 }
652 }
653
654 ObjectId act = inserter.insert(type, raw);
655 if (!AnyObjectId.equals(id, act)) {
656 throw new TransportException(MessageFormat.format(
657 JGitText.get().incorrectHashFor, id.name(), act.name(),
658 Constants.typeString(type),
659 Integer.valueOf(compressed.length)));
660 }
661 }
662
663 private Collection<WalkRemoteObjectDatabase> expandOneAlternate(
664 final AnyObjectId id, final ProgressMonitor pm) {
665 while (!noAlternatesYet.isEmpty()) {
666 final WalkRemoteObjectDatabase wrr = noAlternatesYet.removeFirst();
667 try {
668 pm.beginTask(JGitText.get().listingAlternates, ProgressMonitor.UNKNOWN);
669 Collection<WalkRemoteObjectDatabase> altList = wrr
670 .getAlternates();
671 if (altList != null && !altList.isEmpty())
672 return altList;
673 } catch (IOException e) {
674
675
676 recordError(id, e);
677 } finally {
678 pm.endTask();
679 }
680 }
681 return null;
682 }
683
684 private void markLocalRefsComplete(final Set<ObjectId> have) throws TransportException {
685 Map<String, Ref> refs;
686 try {
687 refs = local.getRefDatabase().getRefs(ALL);
688 } catch (IOException e) {
689 throw new TransportException(e.getMessage(), e);
690 }
691 for (final Ref r : refs.values()) {
692 try {
693 markLocalObjComplete(revWalk.parseAny(r.getObjectId()));
694 } catch (IOException readError) {
695 throw new TransportException(MessageFormat.format(JGitText.get().localRefIsMissingObjects, r.getName()), readError);
696 }
697 }
698 for (final ObjectId id : have) {
699 try {
700 markLocalObjComplete(revWalk.parseAny(id));
701 } catch (IOException readError) {
702 throw new TransportException(MessageFormat.format(JGitText.get().transportExceptionMissingAssumed, id.name()), readError);
703 }
704 }
705 }
706
707 private void markLocalObjComplete(RevObject obj) throws IOException {
708 while (obj.getType() == Constants.OBJ_TAG) {
709 obj.add(COMPLETE);
710 obj = ((RevTag) obj).getObject();
711 revWalk.parseHeaders(obj);
712 }
713
714 switch (obj.getType()) {
715 case Constants.OBJ_BLOB:
716 obj.add(COMPLETE);
717 break;
718 case Constants.OBJ_COMMIT:
719 pushLocalCommit((RevCommit) obj);
720 break;
721 case Constants.OBJ_TREE:
722 markTreeComplete((RevTree) obj);
723 break;
724 }
725 }
726
727 private void markLocalCommitsComplete(final int until)
728 throws TransportException {
729 try {
730 for (;;) {
731 final RevCommit c = localCommitQueue.peek();
732 if (c == null || c.getCommitTime() < until)
733 return;
734 localCommitQueue.next();
735
736 markTreeComplete(c.getTree());
737 for (final RevCommit p : c.getParents())
738 pushLocalCommit(p);
739 }
740 } catch (IOException err) {
741 throw new TransportException(JGitText.get().localObjectsIncomplete, err);
742 }
743 }
744
745 private void pushLocalCommit(final RevCommit p)
746 throws MissingObjectException, IOException {
747 if (p.has(LOCALLY_SEEN))
748 return;
749 revWalk.parseHeaders(p);
750 p.add(LOCALLY_SEEN);
751 p.add(COMPLETE);
752 p.carry(COMPLETE);
753 localCommitQueue.add(p);
754 }
755
756 private void markTreeComplete(final RevTree tree) throws IOException {
757 if (tree.has(COMPLETE))
758 return;
759 tree.add(COMPLETE);
760 treeWalk.reset(tree);
761 while (treeWalk.next()) {
762 final FileMode mode = treeWalk.getFileMode(0);
763 final int sType = mode.getObjectType();
764
765 switch (sType) {
766 case Constants.OBJ_BLOB:
767 treeWalk.getObjectId(idBuffer, 0);
768 revWalk.lookupAny(idBuffer, sType).add(COMPLETE);
769 continue;
770
771 case Constants.OBJ_TREE: {
772 treeWalk.getObjectId(idBuffer, 0);
773 final RevObject o = revWalk.lookupAny(idBuffer, sType);
774 if (!o.has(COMPLETE)) {
775 o.add(COMPLETE);
776 treeWalk.enterSubtree();
777 }
778 continue;
779 }
780 default:
781 if (FileMode.GITLINK.equals(mode))
782 continue;
783 treeWalk.getObjectId(idBuffer, 0);
784 throw new CorruptObjectException(MessageFormat.format(JGitText.get().corruptObjectInvalidMode3
785 , mode, idBuffer.name(), treeWalk.getPathString(), tree.name()));
786 }
787 }
788 }
789
790 private void recordError(final AnyObjectId id, final Throwable what) {
791 final ObjectId objId = id.copy();
792 List<Throwable> errors = fetchErrors.get(objId);
793 if (errors == null) {
794 errors = new ArrayList<Throwable>(2);
795 fetchErrors.put(objId, errors);
796 }
797 errors.add(what);
798 }
799
800 private class RemotePack {
801 final WalkRemoteObjectDatabase connection;
802
803 final String packName;
804
805 final String idxName;
806
807 File tmpIdx;
808
809 PackIndex index;
810
811 RemotePack(final WalkRemoteObjectDatabase c, final String pn) {
812 connection = c;
813 packName = pn;
814 idxName = packName.substring(0, packName.length() - 5) + ".idx";
815
816 String tn = idxName;
817 if (tn.startsWith("pack-"))
818 tn = tn.substring(5);
819 if (tn.endsWith(".idx"))
820 tn = tn.substring(0, tn.length() - 4);
821
822 if (local.getObjectDatabase() instanceof ObjectDirectory) {
823 tmpIdx = new File(((ObjectDirectory) local.getObjectDatabase())
824 .getDirectory(),
825 "walk-" + tn + ".walkidx");
826 }
827 }
828
829 void openIndex(final ProgressMonitor pm) throws IOException {
830 if (index != null)
831 return;
832 if (tmpIdx == null)
833 tmpIdx = File.createTempFile("jgit-walk-", ".idx");
834 else if (tmpIdx.isFile()) {
835 try {
836 index = PackIndex.open(tmpIdx);
837 return;
838 } catch (FileNotFoundException err) {
839
840 }
841 }
842
843 final WalkRemoteObjectDatabase.FileStream s;
844 s = connection.open("pack/" + idxName);
845 pm.beginTask("Get " + idxName.substring(0, 12) + "..idx",
846 s.length < 0 ? ProgressMonitor.UNKNOWN
847 : (int) (s.length / 1024));
848 try {
849 final FileOutputStream fos = new FileOutputStream(tmpIdx);
850 try {
851 final byte[] buf = new byte[2048];
852 int cnt;
853 while (!pm.isCancelled() && (cnt = s.in.read(buf)) >= 0) {
854 fos.write(buf, 0, cnt);
855 pm.update(cnt / 1024);
856 }
857 } finally {
858 fos.close();
859 }
860 } catch (IOException err) {
861 FileUtils.delete(tmpIdx);
862 throw err;
863 } finally {
864 s.in.close();
865 }
866 pm.endTask();
867
868 if (pm.isCancelled()) {
869 FileUtils.delete(tmpIdx);
870 return;
871 }
872
873 try {
874 index = PackIndex.open(tmpIdx);
875 } catch (IOException e) {
876 FileUtils.delete(tmpIdx);
877 throw e;
878 }
879 }
880
881 void downloadPack(final ProgressMonitor monitor) throws IOException {
882 String name = "pack/" + packName;
883 WalkRemoteObjectDatabase.FileStream s = connection.open(name);
884 try {
885 PackParser parser = inserter.newPackParser(s.in);
886 parser.setAllowThin(false);
887 parser.setObjectChecker(objCheck);
888 parser.setLockMessage(lockMessage);
889 PackLock lock = parser.parse(monitor);
890 if (lock != null)
891 packLocks.add(lock);
892 } finally {
893 s.in.close();
894 }
895 }
896 }
897 }