1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.file;
12
13 import java.io.File;
14 import java.io.FileInputStream;
15 import java.io.FileNotFoundException;
16 import java.io.IOException;
17 import java.nio.file.Files;
18 import java.nio.file.NoSuchFileException;
19 import java.nio.file.StandardCopyOption;
20 import java.util.Set;
21
22 import org.eclipse.jgit.internal.storage.file.FileObjectDatabase.InsertLooseObjectResult;
23 import org.eclipse.jgit.lib.AbbreviatedObjectId;
24 import org.eclipse.jgit.lib.AnyObjectId;
25 import org.eclipse.jgit.lib.Constants;
26 import org.eclipse.jgit.lib.ObjectId;
27 import org.eclipse.jgit.lib.ObjectLoader;
28 import org.eclipse.jgit.util.FileUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32
33
34
35
36
37
38
39 class LooseObjects {
40 private static final Logger LOG = LoggerFactory
41 .getLogger(LooseObjects.class);
42
43 private final File directory;
44
45 private final UnpackedObjectCache unpackedObjectCache;
46
47
48
49
50
51
52
53 LooseObjects(File dir) {
54 directory = dir;
55 unpackedObjectCache = new UnpackedObjectCache();
56 }
57
58
59
60
61
62
63 File getDirectory() {
64 return directory;
65 }
66
67 void create() throws IOException {
68 FileUtils.mkdirs(directory);
69 }
70
71 void close() {
72 unpackedObjectCache.clear();
73 }
74
75
76 @Override
77 public String toString() {
78 return "LooseObjects[" + directory + "]";
79 }
80
81 boolean hasCached(AnyObjectId id) {
82 return unpackedObjectCache.isUnpacked(id);
83 }
84
85
86
87
88
89
90
91
92 boolean has(AnyObjectId objectId) {
93 return fileFor(objectId).exists();
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 boolean resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
111 int matchLimit) {
112 String fanOut = id.name().substring(0, 2);
113 String[] entries = new File(directory, fanOut).list();
114 if (entries != null) {
115 for (String e : entries) {
116 if (e.length() != Constants.OBJECT_ID_STRING_LENGTH - 2) {
117 continue;
118 }
119 try {
120 ObjectId entId = ObjectId.fromString(fanOut + e);
121 if (id.prefixCompare(entId) == 0) {
122 matches.add(entId);
123 }
124 } catch (IllegalArgumentException notId) {
125 continue;
126 }
127 if (matches.size() > matchLimit) {
128 return false;
129 }
130 }
131 }
132 return true;
133 }
134
135 ObjectLoader open(WindowCursor curs, AnyObjectId id) throws IOException {
136 File path = fileFor(id);
137 try (FileInputStream in = new FileInputStream(path)) {
138 unpackedObjectCache.add(id);
139 return UnpackedObject.open(in, path, id, curs);
140 } catch (FileNotFoundException noFile) {
141 if (path.exists()) {
142 throw noFile;
143 }
144 unpackedObjectCache.remove(id);
145 return null;
146 }
147 }
148
149 long getSize(WindowCursor curs, AnyObjectId id) throws IOException {
150 File f = fileFor(id);
151 try (FileInputStream in = new FileInputStream(f)) {
152 unpackedObjectCache.add(id);
153 return UnpackedObject.getSize(in, id, curs);
154 } catch (FileNotFoundException noFile) {
155 if (f.exists()) {
156 throw noFile;
157 }
158 unpackedObjectCache.remove(id);
159 return -1;
160 }
161 }
162
163 InsertLooseObjectResult insert(File tmp, ObjectId id) throws IOException {
164 final File dst = fileFor(id);
165 if (dst.exists()) {
166
167
168
169
170 FileUtils.delete(tmp, FileUtils.RETRY);
171 return InsertLooseObjectResult.EXISTS_LOOSE;
172 }
173
174 try {
175 return tryMove(tmp, dst, id);
176 } catch (NoSuchFileException e) {
177
178
179
180
181
182
183 FileUtils.mkdir(dst.getParentFile(), true);
184 } catch (IOException e) {
185
186
187 LOG.error(e.getMessage(), e);
188 FileUtils.delete(tmp, FileUtils.RETRY);
189 return InsertLooseObjectResult.FAILURE;
190 }
191
192 try {
193 return tryMove(tmp, dst, id);
194 } catch (IOException e) {
195
196
197
198
199 LOG.error(e.getMessage(), e);
200 FileUtils.delete(tmp, FileUtils.RETRY);
201 return InsertLooseObjectResult.FAILURE;
202 }
203 }
204
205 private InsertLooseObjectResult tryMove(File tmp, File dst, ObjectId id)
206 throws IOException {
207 Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst),
208 StandardCopyOption.ATOMIC_MOVE);
209 dst.setReadOnly();
210 unpackedObjectCache.add(id);
211 return InsertLooseObjectResult.INSERTED;
212 }
213
214
215
216
217
218
219
220
221 File fileFor(AnyObjectId objectId) {
222 String n = objectId.name();
223 String d = n.substring(0, 2);
224 String f = n.substring(2);
225 return new File(new File(getDirectory(), d), f);
226 }
227 }