1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jgit.dircache;
14
15 import static java.nio.charset.StandardCharsets.ISO_8859_1;
16
17 import java.io.BufferedInputStream;
18 import java.io.BufferedOutputStream;
19 import java.io.EOFException;
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.security.DigestOutputStream;
26 import java.security.MessageDigest;
27 import java.text.MessageFormat;
28 import java.time.Instant;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Comparator;
32 import java.util.List;
33
34 import org.eclipse.jgit.errors.CorruptObjectException;
35 import org.eclipse.jgit.errors.IndexReadException;
36 import org.eclipse.jgit.errors.LockFailedException;
37 import org.eclipse.jgit.errors.UnmergedPathException;
38 import org.eclipse.jgit.events.IndexChangedEvent;
39 import org.eclipse.jgit.events.IndexChangedListener;
40 import org.eclipse.jgit.internal.JGitText;
41 import org.eclipse.jgit.internal.storage.file.FileSnapshot;
42 import org.eclipse.jgit.internal.storage.file.LockFile;
43 import org.eclipse.jgit.lib.AnyObjectId;
44 import org.eclipse.jgit.lib.Config;
45 import org.eclipse.jgit.lib.Config.ConfigEnum;
46 import org.eclipse.jgit.lib.ConfigConstants;
47 import org.eclipse.jgit.lib.Constants;
48 import org.eclipse.jgit.lib.ObjectId;
49 import org.eclipse.jgit.lib.ObjectInserter;
50 import org.eclipse.jgit.lib.ObjectReader;
51 import org.eclipse.jgit.lib.Repository;
52 import org.eclipse.jgit.treewalk.FileTreeIterator;
53 import org.eclipse.jgit.treewalk.TreeWalk;
54 import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
55 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
56 import org.eclipse.jgit.util.FS;
57 import org.eclipse.jgit.util.IO;
58 import org.eclipse.jgit.util.MutableInteger;
59 import org.eclipse.jgit.util.NB;
60 import org.eclipse.jgit.util.TemporaryBuffer;
61 import org.eclipse.jgit.util.io.SilentFileInputStream;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public class DirCache {
77 private static final byte[] SIG_DIRC = { 'D', 'I', 'R', 'C' };
78
79 private static final int EXT_TREE = 0x54524545 ;
80
81 private static final DirCacheEntry[] NO_ENTRIES = {};
82
83 private static final byte[] NO_CHECKSUM = {};
84
85 static final Comparator<DirCacheEntry> ENT_CMP = (DirCacheEntry o1,
86 DirCacheEntry o2) -> {
87 final int cr = cmp(o1, o2);
88 if (cr != 0)
89 return cr;
90 return o1.getStage() - o2.getStage();
91 };
92
93 static int cmp(DirCacheEntry../../../../org/eclipse/jgit/dircache/DirCacheEntry.html#DirCacheEntry">DirCacheEntry a, DirCacheEntry b) {
94 return cmp(a.path, a.path.length, b);
95 }
96
97 static int cmp(byte[] aPath, int aLen, DirCacheEntry b) {
98 return cmp(aPath, aLen, b.path, b.path.length);
99 }
100
101 static int cmp(final byte[] aPath, final int aLen, final byte[] bPath,
102 final int bLen) {
103 for (int cPos = 0; cPos < aLen && cPos < bLen; cPos++) {
104 final int cmp = (aPath[cPos] & 0xff) - (bPath[cPos] & 0xff);
105 if (cmp != 0)
106 return cmp;
107 }
108 return aLen - bLen;
109 }
110
111
112
113
114
115
116
117
118 public static DirCache newInCore() {
119 return new DirCache(null, null);
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 public static DirCache read(ObjectReader reader, AnyObjectId treeId)
136 throws IOException {
137 DirCache d = newInCore();
138 DirCacheBuilder b = d.builder();
139 b.addTree(null, DirCacheEntry.STAGE_0, reader, treeId);
140 b.finish();
141 return d;
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 public static DirCache read(Repository repository)
162 throws CorruptObjectException, IOException {
163 final DirCache c = read(repository.getIndexFile(), repository.getFS());
164 c.repository = repository;
165 return c;
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 public static DirCache read(File indexLocation, FS fs)
189 throws CorruptObjectException, IOException {
190 final DirCache/DirCache.html#DirCache">DirCache c = new DirCache(indexLocation, fs);
191 c.read();
192 return c;
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 public static DirCache lock(File indexLocation, FS fs)
218 throws CorruptObjectException, IOException {
219 final DirCache/DirCache.html#DirCache">DirCache c = new DirCache(indexLocation, fs);
220 if (!c.lock())
221 throw new LockFailedException(indexLocation);
222
223 try {
224 c.read();
225 } catch (IOException | RuntimeException | Error e) {
226 c.unlock();
227 throw e;
228 }
229
230 return c;
231 }
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 public static DirCache lock(final Repository repository,
256 final IndexChangedListener indexChangedListener)
257 throws CorruptObjectException, IOException {
258 DirCache c = lock(repository.getIndexFile(), repository.getFS(),
259 indexChangedListener);
260 c.repository = repository;
261 return c;
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288 public static DirCache lock(final File indexLocation, final FS fs,
289 IndexChangedListener indexChangedListener)
290 throws CorruptObjectException,
291 IOException {
292 DirCache c = lock(indexLocation, fs);
293 c.registerIndexChangedListener(indexChangedListener);
294 return c;
295 }
296
297
298 private final File liveFile;
299
300
301 private DirCacheEntry[] sortedEntries;
302
303
304 private int entryCnt;
305
306
307 private DirCacheTree tree;
308
309
310 private LockFile myLock;
311
312
313 private FileSnapshot snapshot;
314
315
316 private byte[] readIndexChecksum;
317
318
319 private byte[] writeIndexChecksum;
320
321
322 private IndexChangedListener indexChangedListener;
323
324
325 private Repository repository;
326
327
328 private DirCacheVersion version;
329
330
331
332
333
334
335
336
337
338
339
340
341
342 public DirCache(File indexLocation, FS fs) {
343 liveFile = indexLocation;
344 clear();
345 }
346
347
348
349
350
351
352
353
354
355
356 public DirCacheBuilder builder() {
357 return new DirCacheBuilder(this, entryCnt + 16);
358 }
359
360
361
362
363
364
365
366
367
368
369 public DirCacheEditor editor() {
370 return new DirCacheEditor(this, entryCnt + 16);
371 }
372
373 DirCacheVersion getVersion() {
374 return version;
375 }
376
377 void replace(DirCacheEntry[] e, int cnt) {
378 sortedEntries = e;
379 entryCnt = cnt;
380 tree = null;
381 }
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397 public void read() throws IOException, CorruptObjectException {
398 if (liveFile == null)
399 throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile);
400 if (!liveFile.exists())
401 clear();
402 else if (snapshot == null || snapshot.isModified(liveFile)) {
403 try (SilentFileInputStreamm.html#SilentFileInputStream">SilentFileInputStream inStream = new SilentFileInputStream(
404 liveFile)) {
405 clear();
406 readFrom(inStream);
407 } catch (FileNotFoundException fnfe) {
408 if (liveFile.exists()) {
409
410 throw new IndexReadException(
411 MessageFormat.format(JGitText.get().cannotReadIndex,
412 liveFile.getAbsolutePath(), fnfe));
413 }
414
415
416
417 clear();
418 }
419 snapshot = FileSnapshot.save(liveFile);
420 }
421 }
422
423
424
425
426
427
428
429 public boolean isOutdated() throws IOException {
430 if (liveFile == null || !liveFile.exists())
431 return false;
432 return snapshot == null || snapshot.isModified(liveFile);
433 }
434
435
436
437
438 public void clear() {
439 snapshot = null;
440 sortedEntries = NO_ENTRIES;
441 entryCnt = 0;
442 tree = null;
443 readIndexChecksum = NO_CHECKSUM;
444 }
445
446 private void readFrom(InputStream inStream) throws IOException,
447 CorruptObjectException {
448 final BufferedInputStream in = new BufferedInputStream(inStream);
449 final MessageDigest md = Constants.newMessageDigest();
450
451
452
453 final byte[] hdr = new byte[20];
454 IO.readFully(in, hdr, 0, 12);
455 md.update(hdr, 0, 12);
456 if (!is_DIRC(hdr))
457 throw new CorruptObjectException(JGitText.get().notADIRCFile);
458 int versionCode = NB.decodeInt32(hdr, 4);
459 DirCacheVersion ver = DirCacheVersion.fromInt(versionCode);
460 if (ver == null) {
461 throw new CorruptObjectException(
462 MessageFormat.format(JGitText.get().unknownDIRCVersion,
463 Integer.valueOf(versionCode)));
464 }
465 boolean extended = false;
466 switch (ver) {
467 case DIRC_VERSION_MINIMUM:
468 break;
469 case DIRC_VERSION_EXTENDED:
470 case DIRC_VERSION_PATHCOMPRESS:
471 extended = true;
472 break;
473 default:
474 throw new CorruptObjectException(MessageFormat
475 .format(JGitText.get().unknownDIRCVersion, ver));
476 }
477 version = ver;
478 entryCnt = NB.decodeInt32(hdr, 8);
479 if (entryCnt < 0)
480 throw new CorruptObjectException(JGitText.get().DIRCHasTooManyEntries);
481
482 snapshot = FileSnapshot.save(liveFile);
483 Instant smudge = snapshot.lastModifiedInstant();
484
485
486
487 final int infoLength = DirCacheEntry.getMaximumInfoLength(extended);
488 final byte[] infos = new byte[infoLength * entryCnt];
489 sortedEntries = new DirCacheEntry[entryCnt];
490
491 final MutableInteger.html#MutableInteger">MutableInteger infoAt = new MutableInteger();
492 for (int i = 0; i < entryCnt; i++) {
493 sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md, smudge,
494 version, i == 0 ? null : sortedEntries[i - 1]);
495 }
496
497
498
499 for (;;) {
500 in.mark(21);
501 IO.readFully(in, hdr, 0, 20);
502 if (in.read() < 0) {
503
504
505 break;
506 }
507
508 in.reset();
509 md.update(hdr, 0, 8);
510 IO.skipFully(in, 8);
511
512 long sz = NB.decodeUInt32(hdr, 4);
513 switch (NB.decodeInt32(hdr, 0)) {
514 case EXT_TREE: {
515 if (Integer.MAX_VALUE < sz) {
516 throw new CorruptObjectException(MessageFormat.format(
517 JGitText.get().DIRCExtensionIsTooLargeAt,
518 formatExtensionName(hdr), Long.valueOf(sz)));
519 }
520 final byte[] raw = new byte[(int) sz];
521 IO.readFully(in, raw, 0, raw.length);
522 md.update(raw, 0, raw.length);
523 tree = new DirCacheTree(raw, new MutableInteger(), null);
524 break;
525 }
526 default:
527 if (hdr[0] >= 'A' && hdr[0] <= 'Z') {
528
529
530
531
532
533 skipOptionalExtension(in, md, hdr, sz);
534 } else {
535
536
537
538
539 throw new CorruptObjectException(MessageFormat.format(JGitText.get().DIRCExtensionNotSupportedByThisVersion
540 , formatExtensionName(hdr)));
541 }
542 }
543 }
544
545 readIndexChecksum = md.digest();
546 if (!Arrays.equals(readIndexChecksum, hdr)) {
547 throw new CorruptObjectException(JGitText.get().DIRCChecksumMismatch);
548 }
549 }
550
551 private void skipOptionalExtension(final InputStream in,
552 final MessageDigest md, final byte[] hdr, long sz)
553 throws IOException {
554 final byte[] b = new byte[4096];
555 while (0 < sz) {
556 int n = in.read(b, 0, (int) Math.min(b.length, sz));
557 if (n < 0) {
558 throw new EOFException(
559 MessageFormat.format(
560 JGitText.get().shortReadOfOptionalDIRCExtensionExpectedAnotherBytes,
561 formatExtensionName(hdr), Long.valueOf(sz)));
562 }
563 md.update(b, 0, n);
564 sz -= n;
565 }
566 }
567
568 private static String formatExtensionName(byte[] hdr) {
569 return "'" + new String(hdr, 0, 4, ISO_8859_1) + "'";
570 }
571
572 private static boolean is_DIRC(byte[] hdr) {
573 if (hdr.length < SIG_DIRC.length)
574 return false;
575 for (int i = 0; i < SIG_DIRC.length; i++)
576 if (hdr[i] != SIG_DIRC[i])
577 return false;
578 return true;
579 }
580
581
582
583
584
585
586
587
588
589
590 public boolean lock() throws IOException {
591 if (liveFile == null)
592 throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile);
593 final LockFiletorage/file/LockFile.html#LockFile">LockFile tmp = new LockFile(liveFile);
594 if (tmp.lock()) {
595 tmp.setNeedStatInformation(true);
596 myLock = tmp;
597 return true;
598 }
599 return false;
600 }
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 public void write() throws IOException {
618 final LockFile tmp = myLock;
619 requireLocked(tmp);
620 try (OutputStream o = tmp.getOutputStream();
621 OutputStream bo = new BufferedOutputStream(o)) {
622 writeTo(liveFile.getParentFile(), bo);
623 } catch (IOException | RuntimeException | Error err) {
624 tmp.unlock();
625 throw err;
626 }
627 }
628
629 void writeTo(File dir, OutputStream os) throws IOException {
630 final MessageDigest foot = Constants.newMessageDigest();
631 final DigestOutputStream dos = new DigestOutputStream(os, foot);
632
633 if (version == null && this.repository != null) {
634
635 DirCacheConfig config = repository.getConfig()
636 .get(DirCacheConfig::new);
637 version = config.getIndexVersion();
638 }
639 if (version == null
640 || version == DirCacheVersion.DIRC_VERSION_MINIMUM) {
641 version = DirCacheVersion.DIRC_VERSION_MINIMUM;
642 for (int i = 0; i < entryCnt; i++) {
643 if (sortedEntries[i].isExtended()) {
644 version = DirCacheVersion.DIRC_VERSION_EXTENDED;
645 break;
646 }
647 }
648 }
649
650
651
652 final byte[] tmp = new byte[128];
653 System.arraycopy(SIG_DIRC, 0, tmp, 0, SIG_DIRC.length);
654 NB.encodeInt32(tmp, 4, version.getVersionCode());
655 NB.encodeInt32(tmp, 8, entryCnt);
656 dos.write(tmp, 0, 12);
657
658
659
660 Instant smudge;
661 if (myLock != null) {
662
663
664
665
666 myLock.createCommitSnapshot();
667 snapshot = myLock.getCommitSnapshot();
668 smudge = snapshot.lastModifiedInstant();
669 } else {
670
671 smudge = Instant.EPOCH;
672 }
673
674
675
676 final boolean writeTree = tree != null;
677
678 if (repository != null && entryCnt > 0)
679 updateSmudgedEntries();
680
681 for (int i = 0; i < entryCnt; i++) {
682 final DirCacheEntry e = sortedEntries[i];
683 if (e.mightBeRacilyClean(smudge)) {
684 e.smudgeRacilyClean();
685 }
686 e.write(dos, version, i == 0 ? null : sortedEntries[i - 1]);
687 }
688
689 if (writeTree) {
690 @SuppressWarnings("resource")
691
692 TemporaryBuffer bb = new TemporaryBuffer.LocalFile(dir, 5 << 20);
693 try {
694 tree.write(tmp, bb);
695 bb.close();
696
697 NB.encodeInt32(tmp, 0, EXT_TREE);
698 NB.encodeInt32(tmp, 4, (int) bb.length());
699 dos.write(tmp, 0, 8);
700 bb.writeTo(dos, null);
701 } finally {
702 bb.destroy();
703 }
704 }
705 writeIndexChecksum = foot.digest();
706 os.write(writeIndexChecksum);
707 os.close();
708 }
709
710
711
712
713
714
715
716
717
718
719
720
721 public boolean commit() {
722 final LockFile tmp = myLock;
723 requireLocked(tmp);
724 myLock = null;
725 if (!tmp.commit()) {
726 return false;
727 }
728 snapshot = tmp.getCommitSnapshot();
729 if (indexChangedListener != null
730 && !Arrays.equals(readIndexChecksum, writeIndexChecksum)) {
731 indexChangedListener.onIndexChanged(new IndexChangedEvent(true));
732 }
733 return true;
734 }
735
736 private void requireLocked(LockFile tmp) {
737 if (liveFile == null)
738 throw new IllegalStateException(JGitText.get().dirCacheIsNotLocked);
739 if (tmp == null)
740 throw new IllegalStateException(MessageFormat.format(JGitText.get().dirCacheFileIsNotLocked
741 , liveFile.getAbsolutePath()));
742 }
743
744
745
746
747
748
749 public void unlock() {
750 final LockFile tmp = myLock;
751 if (tmp != null) {
752 myLock = null;
753 tmp.unlock();
754 }
755 }
756
757
758
759
760
761
762
763
764
765
766
767 public int findEntry(String path) {
768 final byte[] p = Constants.encode(path);
769 return findEntry(p, p.length);
770 }
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791 public int findEntry(byte[] p, int pLen) {
792 return findEntry(0, p, pLen);
793 }
794
795 int findEntry(int low, byte[] p, int pLen) {
796 int high = entryCnt;
797 while (low < high) {
798 int mid = (low + high) >>> 1;
799 final int cmp = cmp(p, pLen, sortedEntries[mid]);
800 if (cmp < 0)
801 high = mid;
802 else if (cmp == 0) {
803 while (mid > 0 && cmp(p, pLen, sortedEntries[mid - 1]) == 0)
804 mid--;
805 return mid;
806 } else
807 low = mid + 1;
808 }
809 return -(low + 1);
810 }
811
812
813
814
815
816
817
818
819
820
821
822
823 public int nextEntry(int position) {
824 DirCacheEntry last = sortedEntries[position];
825 int nextIdx = position + 1;
826 while (nextIdx < entryCnt) {
827 final DirCacheEntry next = sortedEntries[nextIdx];
828 if (cmp(last, next) != 0)
829 break;
830 last = next;
831 nextIdx++;
832 }
833 return nextIdx;
834 }
835
836 int nextEntry(byte[] p, int pLen, int nextIdx) {
837 while (nextIdx < entryCnt) {
838 final DirCacheEntry next = sortedEntries[nextIdx];
839 if (!DirCacheTree.peq(p, next.path, pLen))
840 break;
841 nextIdx++;
842 }
843 return nextIdx;
844 }
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859 public int getEntryCount() {
860 return entryCnt;
861 }
862
863
864
865
866
867
868
869
870 public DirCacheEntry getEntry(int i) {
871 return sortedEntries[i];
872 }
873
874
875
876
877
878
879
880
881 public DirCacheEntry getEntry(String path) {
882 final int i = findEntry(path);
883 return i < 0 ? null : sortedEntries[i];
884 }
885
886
887
888
889
890
891
892
893 public DirCacheEntry[] getEntriesWithin(String path) {
894 if (path.length() == 0) {
895 DirCacheEntry[] r = new DirCacheEntry[entryCnt];
896 System.arraycopy(sortedEntries, 0, r, 0, entryCnt);
897 return r;
898 }
899 if (!path.endsWith("/"))
900 path += "/";
901 final byte[] p = Constants.encode(path);
902 final int pLen = p.length;
903
904 int eIdx = findEntry(p, pLen);
905 if (eIdx < 0)
906 eIdx = -(eIdx + 1);
907 final int lastIdx = nextEntry(p, pLen, eIdx);
908 final DirCacheEntryheEntry.html#DirCacheEntry">DirCacheEntry[] r = new DirCacheEntry[lastIdx - eIdx];
909 System.arraycopy(sortedEntries, eIdx, r, 0, r.length);
910 return r;
911 }
912
913 void toArray(final int i, final DirCacheEntry[] dst, final int off,
914 final int cnt) {
915 System.arraycopy(sortedEntries, i, dst, off, cnt);
916 }
917
918
919
920
921
922
923
924
925
926
927
928
929
930 public DirCacheTree getCacheTree(boolean build) {
931 if (build) {
932 if (tree == null)
933 tree = new DirCacheTree();
934 tree.validate(sortedEntries, entryCnt, 0, 0);
935 }
936 return tree;
937 }
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956 public ObjectId writeTree(ObjectInserter ow)
957 throws UnmergedPathException, IOException {
958 return getCacheTree(true).writeTree(sortedEntries, 0, 0, ow);
959 }
960
961
962
963
964
965
966
967
968 public boolean hasUnmergedPaths() {
969 for (int i = 0; i < entryCnt; i++) {
970 if (sortedEntries[i].getStage() > 0) {
971 return true;
972 }
973 }
974 return false;
975 }
976
977 private void registerIndexChangedListener(IndexChangedListener listener) {
978 this.indexChangedListener = listener;
979 }
980
981
982
983
984
985
986 private void updateSmudgedEntries() throws IOException {
987 List<String> paths = new ArrayList<>(128);
988 try (TreeWalkeeWalk.html#TreeWalk">TreeWalk walk = new TreeWalk(repository)) {
989 walk.setOperationType(OperationType.CHECKIN_OP);
990 for (int i = 0; i < entryCnt; i++)
991 if (sortedEntries[i].isSmudged())
992 paths.add(sortedEntries[i].getPathString());
993 if (paths.isEmpty())
994 return;
995 walk.setFilter(PathFilterGroup.createFromStrings(paths));
996
997 DirCacheIterator iIter = new DirCacheIterator(this);
998 FileTreeIterator fIter = new FileTreeIterator(repository);
999 walk.addTree(iIter);
1000 walk.addTree(fIter);
1001 fIter.setDirCacheIterator(walk, 0);
1002 walk.setRecursive(true);
1003 while (walk.next()) {
1004 iIter = walk.getTree(0, DirCacheIterator.class);
1005 if (iIter == null)
1006 continue;
1007 fIter = walk.getTree(1, FileTreeIterator.class);
1008 if (fIter == null)
1009 continue;
1010 DirCacheEntry entry = iIter.getDirCacheEntry();
1011 if (entry.isSmudged() && iIter.idEqual(fIter)) {
1012 entry.setLength(fIter.getEntryLength());
1013 entry.setLastModified(fIter.getEntryLastModifiedInstant());
1014 }
1015 }
1016 }
1017 }
1018
1019 enum DirCacheVersion implements ConfigEnum {
1020
1021
1022 DIRC_VERSION_MINIMUM(2),
1023
1024 DIRC_VERSION_EXTENDED(3),
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034 DIRC_VERSION_PATHCOMPRESS(4);
1035
1036 private final int version;
1037
1038 private DirCacheVersion(int versionCode) {
1039 this.version = versionCode;
1040 }
1041
1042 public int getVersionCode() {
1043 return version;
1044 }
1045
1046 @Override
1047 public String toConfigValue() {
1048 return Integer.toString(version);
1049 }
1050
1051 @Override
1052 public boolean matchConfigValue(String in) {
1053 try {
1054 return version == Integer.parseInt(in);
1055 } catch (NumberFormatException e) {
1056 return false;
1057 }
1058 }
1059
1060 public static DirCacheVersion fromInt(int val) {
1061 for (DirCacheVersion v : DirCacheVersion.values()) {
1062 if (val == v.getVersionCode()) {
1063 return v;
1064 }
1065 }
1066 return null;
1067 }
1068 }
1069
1070 private static class DirCacheConfig {
1071
1072 private final DirCacheVersion indexVersion;
1073
1074 public DirCacheConfig(Config cfg) {
1075 boolean manyFiles = cfg.getBoolean(
1076 ConfigConstants.CONFIG_FEATURE_SECTION,
1077 ConfigConstants.CONFIG_KEY_MANYFILES, false);
1078 indexVersion = cfg.getEnum(DirCacheVersion.values(),
1079 ConfigConstants.CONFIG_INDEX_SECTION, null,
1080 ConfigConstants.CONFIG_KEY_VERSION,
1081 manyFiles ? DirCacheVersion.DIRC_VERSION_PATHCOMPRESS
1082 : DirCacheVersion.DIRC_VERSION_EXTENDED);
1083 }
1084
1085 public DirCacheVersion getIndexVersion() {
1086 return indexVersion;
1087 }
1088
1089 }
1090 }