1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.transport.resolver;
12
13 import java.io.File;
14 import java.io.IOException;
15 import java.util.Collection;
16 import java.util.Map;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.CopyOnWriteArrayList;
19
20 import org.eclipse.jgit.errors.RepositoryNotFoundException;
21 import org.eclipse.jgit.lib.Constants;
22 import org.eclipse.jgit.lib.Repository;
23 import org.eclipse.jgit.lib.RepositoryCache;
24 import org.eclipse.jgit.lib.RepositoryCache.FileKey;
25 import org.eclipse.jgit.util.FS;
26
27
28
29
30
31
32
33 public class FileResolver<C> implements RepositoryResolver<C> {
34 private volatile boolean exportAll;
35
36 private final Map<String, Repository> exports;
37
38 private final Collection<File> exportBase;
39
40
41
42
43 public FileResolver() {
44 exports = new ConcurrentHashMap<>();
45 exportBase = new CopyOnWriteArrayList<>();
46 }
47
48
49
50
51
52
53
54
55
56
57 public FileResolver(File basePath, boolean exportAll) {
58 this();
59 exportDirectory(basePath);
60 setExportAll(exportAll);
61 }
62
63
64 @Override
65 public Repository open(C req, String name)
66 throws RepositoryNotFoundException, ServiceNotEnabledException {
67 if (isUnreasonableName(name))
68 throw new RepositoryNotFoundException(name);
69
70 Repository db = exports.get(nameWithDotGit(name));
71 if (db != null) {
72 db.incrementOpen();
73 return db;
74 }
75
76 for (File base : exportBase) {
77 File dir = FileKey.resolve(new File(base, name), FS.DETECTED);
78 if (dir == null)
79 continue;
80
81 try {
82 FileKey key = FileKey.exact(dir, FS.DETECTED);
83 db = RepositoryCache.open(key, true);
84 } catch (IOException e) {
85 throw new RepositoryNotFoundException(name, e);
86 }
87
88 try {
89 if (isExportOk(req, name, db)) {
90
91
92
93 return db;
94 }
95 throw new ServiceNotEnabledException();
96
97 } catch (RuntimeException | IOException e) {
98 db.close();
99 throw new RepositoryNotFoundException(name, e);
100
101 } catch (ServiceNotEnabledException e) {
102 db.close();
103 throw e;
104 }
105 }
106
107 if (exportBase.size() == 1) {
108 File dir = new File(exportBase.iterator().next(), name);
109 throw new RepositoryNotFoundException(name,
110 new RepositoryNotFoundException(dir));
111 }
112
113 throw new RepositoryNotFoundException(name);
114 }
115
116
117
118
119
120
121
122
123
124
125 public boolean isExportAll() {
126 return exportAll;
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public void setExportAll(boolean export) {
142 exportAll = export;
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156 public void exportRepository(String name, Repository db) {
157 exports.put(nameWithDotGit(name), db);
158 }
159
160
161
162
163
164
165
166
167
168 public void exportDirectory(File dir) {
169 exportBase.add(dir);
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 protected boolean isExportOk(C req, String repositoryName, Repository db)
191 throws IOException {
192 if (isExportAll())
193 return true;
194 else if (db.getDirectory() != null)
195 return new File(db.getDirectory(), "git-daemon-export-ok").exists();
196 else
197 return false;
198 }
199
200 private static String nameWithDotGit(String name) {
201 if (name.endsWith(Constants.DOT_GIT_EXT))
202 return name;
203 return name + Constants.DOT_GIT_EXT;
204 }
205
206 private static boolean isUnreasonableName(String name) {
207 if (name.length() == 0)
208 return true;
209
210 if (name.indexOf('\\') >= 0)
211 return true;
212 if (new File(name).isAbsolute())
213 return true;
214
215 if (name.startsWith("../"))
216 return true;
217 if (name.contains("/../"))
218 return true;
219 if (name.contains("/./"))
220 return true;
221 if (name.contains("//")) //$NON-NLS-1$
222 return true;
223
224 return false;
225 }
226 }