]> source.dussan.org Git - gitea.git/commitdiff
When transfering repository and database transaction failed, rollback the renames...
authorLunny Xiao <xiaolunwen@gmail.com>
Fri, 5 Mar 2021 02:28:52 +0000 (10:28 +0800)
committerGitHub <noreply@github.com>
Fri, 5 Mar 2021 02:28:52 +0000 (03:28 +0100)
Fix #14821

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
models/repo_transfer.go

index cf1e16b9c38581d094b6d162cb0cb1e3f9c05734..9f8fd649b6f357f1ebcd793cf4274dcfc338e8a2 100644 (file)
@@ -195,7 +195,39 @@ func CreatePendingRepositoryTransfer(doer, newOwner *User, repoID int64, teams [
 }
 
 // TransferOwnership transfers all corresponding repository items from old user to new one.
-func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error {
+func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err error) {
+       repoRenamed := false
+       wikiRenamed := false
+       oldOwnerName := doer.Name
+
+       defer func() {
+               if !repoRenamed && !wikiRenamed {
+                       return
+               }
+
+               recoverErr := recover()
+               if err == nil && recoverErr == nil {
+                       return
+               }
+
+               if repoRenamed {
+                       if err := os.Rename(RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name)); err != nil {
+                               log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name), err)
+                       }
+               }
+
+               if wikiRenamed {
+                       if err := os.Rename(WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name)); err != nil {
+                               log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name), err)
+                       }
+               }
+
+               if recoverErr != nil {
+                       log.Error("Panic within TransferOwnership: %v\n%s", recoverErr, log.Stack(2))
+                       panic(recoverErr)
+               }
+       }()
+
        sess := x.NewSession()
        defer sess.Close()
        if err := sess.Begin(); err != nil {
@@ -206,6 +238,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
        if err != nil {
                return fmt.Errorf("get new owner '%s': %v", newOwnerName, err)
        }
+       newOwnerName = newOwner.Name // ensure capitalisation matches
 
        // Check if new owner has repository with same name.
        if has, err := isRepositoryExist(sess, newOwner, repo.Name); err != nil {
@@ -215,6 +248,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
        }
 
        oldOwner := repo.Owner
+       oldOwnerName = oldOwner.Name
 
        // Note: we have to set value here to make sure recalculate accesses is based on
        // new owner.
@@ -301,6 +335,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
        if err := os.Rename(RepoPath(oldOwner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil {
                return fmt.Errorf("rename repository directory: %v", err)
        }
+       repoRenamed = true
 
        // Rename remote wiki repository to new path and delete local copy.
        wikiPath := WikiPath(oldOwner.Name, repo.Name)
@@ -312,6 +347,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error
                if err := os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil {
                        return fmt.Errorf("rename repository wiki: %v", err)
                }
+               wikiRenamed = true
        }
 
        if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {