private bool renameLog(RefUpdate src, RefUpdate dst) { FileInfo srcLog = _refdb.logFor(src.getName()); FileInfo dstLog = _refdb.logFor(dst.getName()); if (!srcLog.Exists) { return(true); } if (!rename(srcLog.FullName, dstLog.FullName)) { return(false); } // There be dragons try { int levels = RefDirectory.levelsIn(src.getName()) - 2; RefDirectory.delete(srcLog, levels); return(true); } catch (IOException) { rename(dstLog.FullName, srcLog.FullName); return(false); } }
protected override RefUpdateResult doDelete(RefUpdateResult status) { if (Ref.getLeaf().getStorage() != Storage.New) { _database.delete(this); } return(status); }
protected override RefUpdate.RefUpdateResult doRename() { if (source.getRef().isSymbolic()) { return(RefUpdate.RefUpdateResult.IO_FAILURE); // not supported } var rw = new RevWalk.RevWalk(_refdb.getRepository()); _objId = source.getOldObjectId(); _updateHead = needToUpdateHEAD(); _tmp = _refdb.newTemporaryUpdate(); try { // First backup the source so its never unreachable. _tmp.setNewObjectId(_objId); _tmp.setForceUpdate(true); _tmp.disableRefLog(); switch (_tmp.update(rw)) { case RefUpdate.RefUpdateResult.NEW: case RefUpdate.RefUpdateResult.FORCED: case RefUpdate.RefUpdateResult.NO_CHANGE: break; default: return(_tmp.getResult()); } // Save the source's log under the temporary name, we must do // this before we delete the source, otherwise we lose the log. if (!renameLog(source, _tmp)) { return(RefUpdate.RefUpdateResult.IO_FAILURE); } // If HEAD has to be updated, link it now to destination. // We have to link before we delete, otherwise the delete // fails because its the current branch. RefUpdate dst = destination; if (_updateHead) { if (!linkHEAD(destination)) { renameLog(_tmp, source); return(RefUpdate.RefUpdateResult.LOCK_FAILURE); } // Replace the update operation so HEAD will log the rename. dst = _refdb.newUpdate(Constants.HEAD, false); dst.setRefLogIdent(destination.getRefLogIdent()); dst.setRefLogMessage(destination.getRefLogMessage(), false); } // Delete the source name so its path is free for replacement. source.setExpectedOldObjectId(_objId); source.setForceUpdate(true); source.disableRefLog(); if (source.delete(rw) != RefUpdate.RefUpdateResult.FORCED) { renameLog(_tmp, source); if (_updateHead) { linkHEAD(source); } return(source.getResult()); } // Move the log to the destination. if (!renameLog(_tmp, destination)) { renameLog(_tmp, source); source.setExpectedOldObjectId(ObjectId.ZeroId); source.setNewObjectId(_objId); source.update(rw); if (_updateHead) { linkHEAD(source); } return(RefUpdate.RefUpdateResult.IO_FAILURE); } // Create the destination, logging the rename during the creation. dst.setExpectedOldObjectId(ObjectId.ZeroId); dst.setNewObjectId(_objId); if (dst.update(rw) != RefUpdate.RefUpdateResult.NEW) { // If we didn't create the destination we have to undo // our work. Put the log back and restore source. if (renameLog(destination, _tmp)) { renameLog(_tmp, source); } source.setExpectedOldObjectId(ObjectId.ZeroId); source.setNewObjectId(_objId); source.update(rw); if (_updateHead) { linkHEAD(source); } return(dst.getResult()); } return(RefUpdate.RefUpdateResult.RENAMED); } finally { // Always try to free the temporary name. try { _refdb.delete(_tmp); } catch (IOException) { _refdb.fileFor(_tmp.getName()).Delete(); } } }