From fc1f0dbec4cfef236668f03005337ac7fc148200 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 6 Oct 2026 15:45:31 +0800 Subject: [PATCH] fix: correct RemoveWithRetry error handling (#39619) * Fix #39618 * Follow up #38588 * Remove unrelated errors --- modules/storage/local.go | 2 +- modules/util/file_retry.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index cc8b572dbb3..cd5ed256eea 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -119,7 +119,7 @@ func (l *LocalStorage) Stat(path string) (os.FileInfo, error) { func (l *LocalStorage) deleteEmptyParentDirs(localFullPath string) { for parent := filepath.Dir(localFullPath); len(parent) > len(l.dir); parent = filepath.Dir(parent) { - if err := util.RemoveWithRetry(parent); err != nil && !os.IsNotExist(err) { + if err := os.Remove(parent); err != nil && !os.IsNotExist(err) { // since the target file has been deleted, parent dir error is not related to the file deletion itself. break } diff --git a/modules/util/file_retry.go b/modules/util/file_retry.go index 6328896d5b2..ac156feb915 100644 --- a/modules/util/file_retry.go +++ b/modules/util/file_retry.go @@ -15,19 +15,23 @@ import ( // * the "cat-batch" git process might be running in a goroutine // * there can be a data-race between the "cat-batch" git process cancel+exit and the repo rename // So we need to retry the rename/remove operation for a few times when the "cat-batch" git process is exiting. -// ref: https://github.com/go-gitea/gitea/issues/16427, https://github.com/go-gitea/gitea/issues/16475, https://github.com/go-gitea/gitea/pull/16479 +// ref: https://github.com/go-gitea/gitea/issues/16427, https://github.com/go-gitea/gitea/issues/16475 +// ref: https://github.com/go-gitea/gitea/pull/16435, https://github.com/go-gitea/gitea/pull/16479 // Also some similar problems when removing a file, e.g.: https://github.com/go-gitea/gitea/issues/12339 // // Usually, if no concurrent access to a file, use "os.Xxx", otherwise, use "util.XxxWithRetry" func retryWhenFileBusyInternal(count int, delay time.Duration, f func() error) (err error) { + // Windows: an opened file without share flags can't be removed or renamed: + // Error code 32: The process cannot access the file because it is being used by another process. + // Also, Error code 16 (EBUSY) happens to be "The directory cannot be removed" (the directory is used as a current directory by a process) const errWindowsSharingViolationError = syscall.Errno(32) for range count { err = f() if err == nil { break } - isErrBusy := errors.Is(err, syscall.EBUSY) || errors.Is(err, syscall.ENOTEMPTY) || errors.Is(err, syscall.EPERM) || errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE) + isErrBusy := errors.Is(err, syscall.EBUSY) isErrBusy = isErrBusy || (isOSWindows && errors.Is(err, errWindowsSharingViolationError)) if !isErrBusy { break