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 @Override
99 protected Result doRename() throws IOException {
100 if (source.getRef().isSymbolic())
101 return Result.IO_FAILURE;
102
103 objId = source.getOldObjectId();
104 updateHEAD = needToUpdateHEAD();
105 tmp = refdb.newTemporaryUpdate();
106 try (final RevWalk rw = new RevWalk(refdb.getRepository())) {
107
108 tmp.setNewObjectId(objId);
109 tmp.setForceUpdate(true);
110 tmp.disableRefLog();
111 switch (tmp.update(rw)) {
112 case NEW:
113 case FORCED:
114 case NO_CHANGE:
115 break;
116 default:
117 return tmp.getResult();
118 }
119
120
121
122 if (!renameLog(source, tmp))
123 return Result.IO_FAILURE;
124
125
126
127
128 RefUpdate dst = destination;
129 if (updateHEAD) {
130 if (!linkHEAD(destination)) {
131 renameLog(tmp, source);
132 return Result.LOCK_FAILURE;
133 }
134
135
136 dst = refdb.newUpdate(Constants.HEAD, false);
137 dst.setRefLogIdent(destination.getRefLogIdent());
138 dst.setRefLogMessage(destination.getRefLogMessage(), false);
139 }
140
141
142 source.setExpectedOldObjectId(objId);
143 source.setForceUpdate(true);
144 source.disableRefLog();
145 if (source.delete(rw) != Result.FORCED) {
146 renameLog(tmp, source);
147 if (updateHEAD)
148 linkHEAD(source);
149 return source.getResult();
150 }
151
152
153 if (!renameLog(tmp, destination)) {
154 renameLog(tmp, source);
155 source.setExpectedOldObjectId(ObjectId.zeroId());
156 source.setNewObjectId(objId);
157 source.update(rw);
158 if (updateHEAD)
159 linkHEAD(source);
160 return Result.IO_FAILURE;
161 }
162
163
164 dst.setExpectedOldObjectId(ObjectId.zeroId());
165 dst.setNewObjectId(objId);
166 if (dst.update(rw) != Result.NEW) {
167
168
169 if (renameLog(destination, tmp))
170 renameLog(tmp, source);
171 source.setExpectedOldObjectId(ObjectId.zeroId());
172 source.setNewObjectId(objId);
173 source.update(rw);
174 if (updateHEAD)
175 linkHEAD(source);
176 return dst.getResult();
177 }
178
179 return Result.RENAMED;
180 } finally {
181
182 try {
183 refdb.delete(tmp);
184 } catch (IOException err) {
185 FileUtils.delete(refdb.fileFor(tmp.getName()));
186 }
187 }
188 }
189
190 private boolean renameLog(RefUpdate src, RefUpdate dst) {
191 File srcLog = refdb.getLogWriter().logFor(src.getName());
192 File dstLog = refdb.getLogWriter().logFor(dst.getName());
193
194 if (!srcLog.exists())
195 return true;
196
197 if (!rename(srcLog, dstLog))
198 return false;
199
200 try {
201 final int levels = RefDirectory.levelsIn(src.getName()) - 2;
202 RefDirectory.delete(srcLog, levels);
203 return true;
204 } catch (IOException e) {
205 rename(dstLog, srcLog);
206 return false;
207 }
208 }
209
210 private static boolean rename(File src, File dst) {
211 try {
212 FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
213 return true;
214 } catch (AtomicMoveNotSupportedException e) {
215 LOG.error(e.getMessage(), e);
216 } catch (IOException e) {
217
218 }
219
220 File dir = dst.getParentFile();
221 if ((dir.exists() || !dir.mkdirs()) && !dir.isDirectory())
222 return false;
223 try {
224 FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
225 return true;
226 } catch (IOException e) {
227 LOG.error(e.getMessage(), e);
228 return false;
229 }
230 }
231
232 private boolean linkHEAD(RefUpdate target) {
233 try {
234 RefUpdate u = refdb.newUpdate(Constants.HEAD, false);
235 u.disableRefLog();
236 switch (u.link(target.getName())) {
237 case NEW:
238 case FORCED:
239 case NO_CHANGE:
240 return true;
241 default:
242 return false;
243 }
244 } catch (IOException e) {
245 return false;
246 }
247 }
248 }