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.internal.storage.file;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.nio.file.AtomicMoveNotSupportedException;
50 import java.nio.file.StandardCopyOption;
51
52 import org.eclipse.jgit.lib.Constants;
53 import org.eclipse.jgit.lib.ObjectId;
54 import org.eclipse.jgit.lib.RefRename;
55 import org.eclipse.jgit.lib.RefUpdate;
56 import org.eclipse.jgit.lib.RefUpdate.Result;
57 import org.eclipse.jgit.revwalk.RevWalk;
58 import org.eclipse.jgit.util.FileUtils;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63
64
65
66
67
68
69
70
71
72 class RefDirectoryRename extends RefRename {
73 private static final Logger LOG = LoggerFactory
74 .getLogger(RefDirectoryRename.class);
75
76 private final RefDirectory refdb;
77
78
79
80
81
82
83
84
85 private ObjectId objId;
86
87
88 private boolean updateHEAD;
89
90
91 private RefDirectoryUpdate tmp;
92
93 RefDirectoryRename(RefDirectoryUpdate src, RefDirectoryUpdate dst) {
94 super(src, dst);
95 refdb = src.getRefDatabase();
96 }
97
98
99 @Override
100 protected Result doRename() throws IOException {
101 if (source.getRef().isSymbolic())
102 return Result.IO_FAILURE;
103
104 objId = source.getOldObjectId();
105 updateHEAD = needToUpdateHEAD();
106 tmp = refdb.newTemporaryUpdate();
107 try (final RevWalk rw = new RevWalk(refdb.getRepository())) {
108
109 tmp.setNewObjectId(objId);
110 tmp.setForceUpdate(true);
111 tmp.disableRefLog();
112 switch (tmp.update(rw)) {
113 case NEW:
114 case FORCED:
115 case NO_CHANGE:
116 break;
117 default:
118 return tmp.getResult();
119 }
120
121
122
123 if (!renameLog(source, tmp))
124 return Result.IO_FAILURE;
125
126
127
128
129 RefUpdate dst = destination;
130 if (updateHEAD) {
131 if (!linkHEAD(destination)) {
132 renameLog(tmp, source);
133 return Result.LOCK_FAILURE;
134 }
135
136
137 dst = refdb.newUpdate(Constants.HEAD, false);
138 dst.setRefLogIdent(destination.getRefLogIdent());
139 dst.setRefLogMessage(destination.getRefLogMessage(), false);
140 }
141
142
143 source.setExpectedOldObjectId(objId);
144 source.setForceUpdate(true);
145 source.disableRefLog();
146 if (source.delete(rw) != Result.FORCED) {
147 renameLog(tmp, source);
148 if (updateHEAD)
149 linkHEAD(source);
150 return source.getResult();
151 }
152
153
154 if (!renameLog(tmp, destination)) {
155 renameLog(tmp, source);
156 source.setExpectedOldObjectId(ObjectId.zeroId());
157 source.setNewObjectId(objId);
158 source.update(rw);
159 if (updateHEAD)
160 linkHEAD(source);
161 return Result.IO_FAILURE;
162 }
163
164
165 dst.setExpectedOldObjectId(ObjectId.zeroId());
166 dst.setNewObjectId(objId);
167 if (dst.update(rw) != Result.NEW) {
168
169
170 if (renameLog(destination, tmp))
171 renameLog(tmp, source);
172 source.setExpectedOldObjectId(ObjectId.zeroId());
173 source.setNewObjectId(objId);
174 source.update(rw);
175 if (updateHEAD)
176 linkHEAD(source);
177 return dst.getResult();
178 }
179
180 return Result.RENAMED;
181 } finally {
182
183 try {
184 refdb.delete(tmp);
185 } catch (IOException err) {
186 FileUtils.delete(refdb.fileFor(tmp.getName()));
187 }
188 }
189 }
190
191 private boolean renameLog(RefUpdate src, RefUpdate dst) {
192 File srcLog = refdb.logFor(src.getName());
193 File dstLog = refdb.logFor(dst.getName());
194
195 if (!srcLog.exists())
196 return true;
197
198 if (!rename(srcLog, dstLog))
199 return false;
200
201 try {
202 final int levels = RefDirectory.levelsIn(src.getName()) - 2;
203 RefDirectory.delete(srcLog, levels);
204 return true;
205 } catch (IOException e) {
206 rename(dstLog, srcLog);
207 return false;
208 }
209 }
210
211 private static boolean rename(File src, File dst) {
212 try {
213 FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
214 return true;
215 } catch (AtomicMoveNotSupportedException e) {
216 LOG.error(e.getMessage(), e);
217 } catch (IOException e) {
218
219 }
220
221 File dir = dst.getParentFile();
222 if ((dir.exists() || !dir.mkdirs()) && !dir.isDirectory())
223 return false;
224 try {
225 FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
226 return true;
227 } catch (IOException e) {
228 LOG.error(e.getMessage(), e);
229 return false;
230 }
231 }
232
233 private boolean linkHEAD(RefUpdate target) {
234 try {
235 RefUpdate u = refdb.newUpdate(Constants.HEAD, false);
236 u.disableRefLog();
237 switch (u.link(target.getName())) {
238 case NEW:
239 case FORCED:
240 case NO_CHANGE:
241 return true;
242 default:
243 return false;
244 }
245 } catch (IOException e) {
246 return false;
247 }
248 }
249 }