mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Fixes the reason why #29101 is hard to replicate.
Related #29297
Create a repo with a file with minimum size 4097 bytes (I use 10000) and
execute the following code:
```go
gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, <repo>)
assert.NoError(t, err)
commit, err := gitRepo.GetCommit(<sha>)
assert.NoError(t, err)
entry, err := commit.GetTreeEntryByPath(<file>)
assert.NoError(t, err)
b := entry.Blob()
// Create a reader
r, err := b.DataAsync()
assert.NoError(t, err)
defer r.Close()
// Create a second reader
r2, err := b.DataAsync()
assert.NoError(t, err) // Should be no error but is ErrNotExist
defer r2.Close()
```
The problem is the check in `CatFileBatch`:
79217ea63c/modules/git/repo_base_nogogit.go (L81-L87)
`Buffered() > 0` is used to check if there is a "operation" in progress
at the moment. This is a problem because we can't control the internal
buffer in the `bufio.Reader`. The code above demonstrates a sequence
which initiates an operation for which the code thinks there is no
active processing. The second call to `DataAsync()` therefore reuses the
existing instances instead of creating a new batch reader.
		
	
		
			
				
	
	
		
			128 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2015 The Gogs Authors. All rights reserved.
 | 
						|
// Copyright 2017 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
//go:build !gogit
 | 
						|
 | 
						|
package git
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"path/filepath"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/modules/log"
 | 
						|
)
 | 
						|
 | 
						|
func init() {
 | 
						|
	isGogit = false
 | 
						|
}
 | 
						|
 | 
						|
// Repository represents a Git repository.
 | 
						|
type Repository struct {
 | 
						|
	Path string
 | 
						|
 | 
						|
	tagCache *ObjectCache
 | 
						|
 | 
						|
	gpgSettings *GPGSettings
 | 
						|
 | 
						|
	batchInUse  bool
 | 
						|
	batchCancel context.CancelFunc
 | 
						|
	batchReader *bufio.Reader
 | 
						|
	batchWriter WriteCloserError
 | 
						|
 | 
						|
	checkInUse  bool
 | 
						|
	checkCancel context.CancelFunc
 | 
						|
	checkReader *bufio.Reader
 | 
						|
	checkWriter WriteCloserError
 | 
						|
 | 
						|
	Ctx             context.Context
 | 
						|
	LastCommitCache *LastCommitCache
 | 
						|
 | 
						|
	objectFormat ObjectFormat
 | 
						|
}
 | 
						|
 | 
						|
// openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
 | 
						|
func openRepositoryWithDefaultContext(repoPath string) (*Repository, error) {
 | 
						|
	return OpenRepository(DefaultContext, repoPath)
 | 
						|
}
 | 
						|
 | 
						|
// OpenRepository opens the repository at the given path with the provided context.
 | 
						|
func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
 | 
						|
	repoPath, err := filepath.Abs(repoPath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	} else if !isDir(repoPath) {
 | 
						|
		return nil, errors.New("no such file or directory")
 | 
						|
	}
 | 
						|
 | 
						|
	// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
 | 
						|
	if err := EnsureValidGitRepository(ctx, repoPath); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	repo := &Repository{
 | 
						|
		Path:     repoPath,
 | 
						|
		tagCache: newObjectCache(),
 | 
						|
		Ctx:      ctx,
 | 
						|
	}
 | 
						|
 | 
						|
	repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath)
 | 
						|
	repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath)
 | 
						|
 | 
						|
	repo.objectFormat, err = repo.GetObjectFormat()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return repo, nil
 | 
						|
}
 | 
						|
 | 
						|
// CatFileBatch obtains a CatFileBatch for this repository
 | 
						|
func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
 | 
						|
	if repo.batchCancel == nil || repo.batchInUse {
 | 
						|
		log.Debug("Opening temporary cat file batch for: %s", repo.Path)
 | 
						|
		return CatFileBatch(ctx, repo.Path)
 | 
						|
	}
 | 
						|
	repo.batchInUse = true
 | 
						|
	return repo.batchWriter, repo.batchReader, func() {
 | 
						|
		repo.batchInUse = false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// CatFileBatchCheck obtains a CatFileBatchCheck for this repository
 | 
						|
func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) {
 | 
						|
	if repo.checkCancel == nil || repo.checkInUse {
 | 
						|
		log.Debug("Opening temporary cat file batch-check for: %s", repo.Path)
 | 
						|
		return CatFileBatchCheck(ctx, repo.Path)
 | 
						|
	}
 | 
						|
	repo.checkInUse = true
 | 
						|
	return repo.checkWriter, repo.checkReader, func() {
 | 
						|
		repo.checkInUse = false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (repo *Repository) Close() (err error) {
 | 
						|
	if repo == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	if repo.batchCancel != nil {
 | 
						|
		repo.batchCancel()
 | 
						|
		repo.batchReader = nil
 | 
						|
		repo.batchWriter = nil
 | 
						|
		repo.batchCancel = nil
 | 
						|
		repo.batchInUse = false
 | 
						|
	}
 | 
						|
	if repo.checkCancel != nil {
 | 
						|
		repo.checkCancel()
 | 
						|
		repo.checkCancel = nil
 | 
						|
		repo.checkReader = nil
 | 
						|
		repo.checkWriter = nil
 | 
						|
		repo.checkInUse = false
 | 
						|
	}
 | 
						|
	repo.LastCommitCache = nil
 | 
						|
	repo.tagCache = nil
 | 
						|
	return err
 | 
						|
}
 |