code.gitea.io/gitea@v1.21.7/services/packages/packages.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package packages
     5  
     6  import (
     7  	"context"
     8  	"encoding/hex"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net/url"
    13  	"strings"
    14  
    15  	"code.gitea.io/gitea/models/db"
    16  	packages_model "code.gitea.io/gitea/models/packages"
    17  	repo_model "code.gitea.io/gitea/models/repo"
    18  	user_model "code.gitea.io/gitea/models/user"
    19  	"code.gitea.io/gitea/modules/json"
    20  	"code.gitea.io/gitea/modules/log"
    21  	packages_module "code.gitea.io/gitea/modules/packages"
    22  	"code.gitea.io/gitea/modules/setting"
    23  	"code.gitea.io/gitea/modules/storage"
    24  	"code.gitea.io/gitea/modules/util"
    25  	notify_service "code.gitea.io/gitea/services/notify"
    26  )
    27  
    28  var (
    29  	ErrQuotaTypeSize   = errors.New("maximum allowed package type size exceeded")
    30  	ErrQuotaTotalSize  = errors.New("maximum allowed package storage quota exceeded")
    31  	ErrQuotaTotalCount = errors.New("maximum allowed package count exceeded")
    32  )
    33  
    34  // PackageInfo describes a package
    35  type PackageInfo struct {
    36  	Owner       *user_model.User
    37  	PackageType packages_model.Type
    38  	Name        string
    39  	Version     string
    40  }
    41  
    42  // PackageCreationInfo describes a package to create
    43  type PackageCreationInfo struct {
    44  	PackageInfo
    45  	SemverCompatible  bool
    46  	Creator           *user_model.User
    47  	Metadata          any
    48  	PackageProperties map[string]string
    49  	VersionProperties map[string]string
    50  }
    51  
    52  // PackageFileInfo describes a package file
    53  type PackageFileInfo struct {
    54  	Filename     string
    55  	CompositeKey string
    56  }
    57  
    58  // PackageFileCreationInfo describes a package file to create
    59  type PackageFileCreationInfo struct {
    60  	PackageFileInfo
    61  	Creator           *user_model.User
    62  	Data              packages_module.HashedSizeReader
    63  	IsLead            bool
    64  	Properties        map[string]string
    65  	OverwriteExisting bool
    66  }
    67  
    68  // CreatePackageAndAddFile creates a package with a file. If the same package exists already, ErrDuplicatePackageVersion is returned
    69  func CreatePackageAndAddFile(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
    70  	return createPackageAndAddFile(ctx, pvci, pfci, false)
    71  }
    72  
    73  // CreatePackageOrAddFileToExisting creates a package with a file or adds the file if the package exists already
    74  func CreatePackageOrAddFileToExisting(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
    75  	return createPackageAndAddFile(ctx, pvci, pfci, true)
    76  }
    77  
    78  func createPackageAndAddFile(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
    79  	dbCtx, committer, err := db.TxContext(ctx)
    80  	if err != nil {
    81  		return nil, nil, err
    82  	}
    83  	defer committer.Close()
    84  
    85  	pv, created, err := createPackageAndVersion(dbCtx, pvci, allowDuplicate)
    86  	if err != nil {
    87  		return nil, nil, err
    88  	}
    89  
    90  	pf, pb, blobCreated, err := addFileToPackageVersion(dbCtx, pv, &pvci.PackageInfo, pfci)
    91  	removeBlob := false
    92  	defer func() {
    93  		if blobCreated && removeBlob {
    94  			contentStore := packages_module.NewContentStore()
    95  			if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
    96  				log.Error("Error deleting package blob from content store: %v", err)
    97  			}
    98  		}
    99  	}()
   100  	if err != nil {
   101  		removeBlob = true
   102  		return nil, nil, err
   103  	}
   104  
   105  	if err := committer.Commit(); err != nil {
   106  		removeBlob = true
   107  		return nil, nil, err
   108  	}
   109  
   110  	if created {
   111  		pd, err := packages_model.GetPackageDescriptor(ctx, pv)
   112  		if err != nil {
   113  			return nil, nil, err
   114  		}
   115  
   116  		notify_service.PackageCreate(ctx, pvci.Creator, pd)
   117  	}
   118  
   119  	return pv, pf, nil
   120  }
   121  
   122  func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, bool, error) {
   123  	log.Trace("Creating package: %v, %v, %v, %s, %s, %+v, %+v, %v", pvci.Creator.ID, pvci.Owner.ID, pvci.PackageType, pvci.Name, pvci.Version, pvci.PackageProperties, pvci.VersionProperties, allowDuplicate)
   124  
   125  	packageCreated := true
   126  	p := &packages_model.Package{
   127  		OwnerID:          pvci.Owner.ID,
   128  		Type:             pvci.PackageType,
   129  		Name:             pvci.Name,
   130  		LowerName:        strings.ToLower(pvci.Name),
   131  		SemverCompatible: pvci.SemverCompatible,
   132  	}
   133  	var err error
   134  	if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
   135  		if err == packages_model.ErrDuplicatePackage {
   136  			packageCreated = false
   137  		} else {
   138  			log.Error("Error inserting package: %v", err)
   139  			return nil, false, err
   140  		}
   141  	}
   142  
   143  	if packageCreated {
   144  		for name, value := range pvci.PackageProperties {
   145  			if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, name, value); err != nil {
   146  				log.Error("Error setting package property: %v", err)
   147  				return nil, false, err
   148  			}
   149  		}
   150  	}
   151  
   152  	metadataJSON, err := json.Marshal(pvci.Metadata)
   153  	if err != nil {
   154  		return nil, false, err
   155  	}
   156  
   157  	versionCreated := true
   158  	pv := &packages_model.PackageVersion{
   159  		PackageID:    p.ID,
   160  		CreatorID:    pvci.Creator.ID,
   161  		Version:      pvci.Version,
   162  		LowerVersion: strings.ToLower(pvci.Version),
   163  		MetadataJSON: string(metadataJSON),
   164  	}
   165  	if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
   166  		if err == packages_model.ErrDuplicatePackageVersion {
   167  			versionCreated = false
   168  		}
   169  		if err != packages_model.ErrDuplicatePackageVersion || !allowDuplicate {
   170  			log.Error("Error inserting package: %v", err)
   171  			return nil, false, err
   172  		}
   173  	}
   174  
   175  	if versionCreated {
   176  		if err := CheckCountQuotaExceeded(ctx, pvci.Creator, pvci.Owner); err != nil {
   177  			return nil, false, err
   178  		}
   179  
   180  		for name, value := range pvci.VersionProperties {
   181  			if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, name, value); err != nil {
   182  				log.Error("Error setting package version property: %v", err)
   183  				return nil, false, err
   184  			}
   185  		}
   186  	}
   187  
   188  	return pv, versionCreated, nil
   189  }
   190  
   191  // AddFileToExistingPackage adds a file to an existing package. If the package does not exist, ErrPackageNotExist is returned
   192  func AddFileToExistingPackage(ctx context.Context, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) {
   193  	return addFileToPackageWrapper(ctx, func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
   194  		pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
   195  		if err != nil {
   196  			return nil, nil, false, err
   197  		}
   198  
   199  		return addFileToPackageVersion(ctx, pv, pvi, pfci)
   200  	})
   201  }
   202  
   203  // AddFileToPackageVersionInternal adds a file to the package
   204  // This method skips quota checks and should only be used for system-managed packages.
   205  func AddFileToPackageVersionInternal(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) {
   206  	return addFileToPackageWrapper(ctx, func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
   207  		return addFileToPackageVersionUnchecked(ctx, pv, pfci)
   208  	})
   209  }
   210  
   211  func addFileToPackageWrapper(ctx context.Context, fn func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error)) (*packages_model.PackageFile, error) {
   212  	ctx, committer, err := db.TxContext(ctx)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	defer committer.Close()
   217  
   218  	pf, pb, blobCreated, err := fn(ctx)
   219  	removeBlob := false
   220  	defer func() {
   221  		if removeBlob {
   222  			contentStore := packages_module.NewContentStore()
   223  			if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
   224  				log.Error("Error deleting package blob from content store: %v", err)
   225  			}
   226  		}
   227  	}()
   228  	if err != nil {
   229  		removeBlob = blobCreated
   230  		return nil, err
   231  	}
   232  
   233  	if err := committer.Commit(); err != nil {
   234  		removeBlob = blobCreated
   235  		return nil, err
   236  	}
   237  
   238  	return pf, nil
   239  }
   240  
   241  // NewPackageBlob creates a package blob instance
   242  func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.PackageBlob {
   243  	hashMD5, hashSHA1, hashSHA256, hashSHA512 := hsr.Sums()
   244  
   245  	return &packages_model.PackageBlob{
   246  		Size:       hsr.Size(),
   247  		HashMD5:    hex.EncodeToString(hashMD5),
   248  		HashSHA1:   hex.EncodeToString(hashSHA1),
   249  		HashSHA256: hex.EncodeToString(hashSHA256),
   250  		HashSHA512: hex.EncodeToString(hashSHA512),
   251  	}
   252  }
   253  
   254  func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
   255  	if err := CheckSizeQuotaExceeded(ctx, pfci.Creator, pvi.Owner, pvi.PackageType, pfci.Data.Size()); err != nil {
   256  		return nil, nil, false, err
   257  	}
   258  
   259  	return addFileToPackageVersionUnchecked(ctx, pv, pfci)
   260  }
   261  
   262  func addFileToPackageVersionUnchecked(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
   263  	log.Trace("Adding package file: %v, %s", pv.ID, pfci.Filename)
   264  
   265  	pb, exists, err := packages_model.GetOrInsertBlob(ctx, NewPackageBlob(pfci.Data))
   266  	if err != nil {
   267  		log.Error("Error inserting package blob: %v", err)
   268  		return nil, nil, false, err
   269  	}
   270  	if !exists {
   271  		contentStore := packages_module.NewContentStore()
   272  		if err := contentStore.Save(packages_module.BlobHash256Key(pb.HashSHA256), pfci.Data, pfci.Data.Size()); err != nil {
   273  			log.Error("Error saving package blob in content store: %v", err)
   274  			return nil, nil, false, err
   275  		}
   276  	}
   277  
   278  	if pfci.OverwriteExisting {
   279  		pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfci.Filename, pfci.CompositeKey)
   280  		if err != nil && err != packages_model.ErrPackageFileNotExist {
   281  			return nil, pb, !exists, err
   282  		}
   283  		if pf != nil {
   284  			// Short circuit if blob is the same
   285  			if pf.BlobID == pb.ID {
   286  				return pf, pb, !exists, nil
   287  			}
   288  
   289  			if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
   290  				return nil, pb, !exists, err
   291  			}
   292  			if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
   293  				return nil, pb, !exists, err
   294  			}
   295  		}
   296  	}
   297  
   298  	pf := &packages_model.PackageFile{
   299  		VersionID:    pv.ID,
   300  		BlobID:       pb.ID,
   301  		Name:         pfci.Filename,
   302  		LowerName:    strings.ToLower(pfci.Filename),
   303  		CompositeKey: pfci.CompositeKey,
   304  		IsLead:       pfci.IsLead,
   305  	}
   306  	if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
   307  		if err != packages_model.ErrDuplicatePackageFile {
   308  			log.Error("Error inserting package file: %v", err)
   309  		}
   310  		return nil, pb, !exists, err
   311  	}
   312  
   313  	for name, value := range pfci.Properties {
   314  		if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeFile, pf.ID, name, value); err != nil {
   315  			log.Error("Error setting package file property: %v", err)
   316  			return pf, pb, !exists, err
   317  		}
   318  	}
   319  
   320  	return pf, pb, !exists, nil
   321  }
   322  
   323  // CheckCountQuotaExceeded checks if the owner has more than the allowed packages
   324  // The check is skipped if the doer is an admin.
   325  func CheckCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User) error {
   326  	if doer.IsAdmin {
   327  		return nil
   328  	}
   329  
   330  	if setting.Packages.LimitTotalOwnerCount > -1 {
   331  		totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
   332  			OwnerID:    owner.ID,
   333  			IsInternal: util.OptionalBoolFalse,
   334  		})
   335  		if err != nil {
   336  			log.Error("CountVersions failed: %v", err)
   337  			return err
   338  		}
   339  		if totalCount > setting.Packages.LimitTotalOwnerCount {
   340  			return ErrQuotaTotalCount
   341  		}
   342  	}
   343  
   344  	return nil
   345  }
   346  
   347  // CheckSizeQuotaExceeded checks if the upload size is bigger than the allowed size
   348  // The check is skipped if the doer is an admin.
   349  func CheckSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, packageType packages_model.Type, uploadSize int64) error {
   350  	if doer.IsAdmin {
   351  		return nil
   352  	}
   353  
   354  	var typeSpecificSize int64
   355  	switch packageType {
   356  	case packages_model.TypeAlpine:
   357  		typeSpecificSize = setting.Packages.LimitSizeAlpine
   358  	case packages_model.TypeCargo:
   359  		typeSpecificSize = setting.Packages.LimitSizeCargo
   360  	case packages_model.TypeChef:
   361  		typeSpecificSize = setting.Packages.LimitSizeChef
   362  	case packages_model.TypeComposer:
   363  		typeSpecificSize = setting.Packages.LimitSizeComposer
   364  	case packages_model.TypeConan:
   365  		typeSpecificSize = setting.Packages.LimitSizeConan
   366  	case packages_model.TypeConda:
   367  		typeSpecificSize = setting.Packages.LimitSizeConda
   368  	case packages_model.TypeContainer:
   369  		typeSpecificSize = setting.Packages.LimitSizeContainer
   370  	case packages_model.TypeCran:
   371  		typeSpecificSize = setting.Packages.LimitSizeCran
   372  	case packages_model.TypeDebian:
   373  		typeSpecificSize = setting.Packages.LimitSizeDebian
   374  	case packages_model.TypeGeneric:
   375  		typeSpecificSize = setting.Packages.LimitSizeGeneric
   376  	case packages_model.TypeGo:
   377  		typeSpecificSize = setting.Packages.LimitSizeGo
   378  	case packages_model.TypeHelm:
   379  		typeSpecificSize = setting.Packages.LimitSizeHelm
   380  	case packages_model.TypeMaven:
   381  		typeSpecificSize = setting.Packages.LimitSizeMaven
   382  	case packages_model.TypeNpm:
   383  		typeSpecificSize = setting.Packages.LimitSizeNpm
   384  	case packages_model.TypeNuGet:
   385  		typeSpecificSize = setting.Packages.LimitSizeNuGet
   386  	case packages_model.TypePub:
   387  		typeSpecificSize = setting.Packages.LimitSizePub
   388  	case packages_model.TypePyPI:
   389  		typeSpecificSize = setting.Packages.LimitSizePyPI
   390  	case packages_model.TypeRpm:
   391  		typeSpecificSize = setting.Packages.LimitSizeRpm
   392  	case packages_model.TypeRubyGems:
   393  		typeSpecificSize = setting.Packages.LimitSizeRubyGems
   394  	case packages_model.TypeSwift:
   395  		typeSpecificSize = setting.Packages.LimitSizeSwift
   396  	case packages_model.TypeVagrant:
   397  		typeSpecificSize = setting.Packages.LimitSizeVagrant
   398  	}
   399  	if typeSpecificSize > -1 && typeSpecificSize < uploadSize {
   400  		return ErrQuotaTypeSize
   401  	}
   402  
   403  	if setting.Packages.LimitTotalOwnerSize > -1 {
   404  		totalSize, err := packages_model.CalculateFileSize(ctx, &packages_model.PackageFileSearchOptions{
   405  			OwnerID: owner.ID,
   406  		})
   407  		if err != nil {
   408  			log.Error("CalculateFileSize failed: %v", err)
   409  			return err
   410  		}
   411  		if totalSize+uploadSize > setting.Packages.LimitTotalOwnerSize {
   412  			return ErrQuotaTotalSize
   413  		}
   414  	}
   415  
   416  	return nil
   417  }
   418  
   419  // GetOrCreateInternalPackageVersion gets or creates an internal package
   420  // Some package types need such internal packages for housekeeping.
   421  func GetOrCreateInternalPackageVersion(ctx context.Context, ownerID int64, packageType packages_model.Type, name, version string) (*packages_model.PackageVersion, error) {
   422  	var pv *packages_model.PackageVersion
   423  
   424  	return pv, db.WithTx(ctx, func(ctx context.Context) error {
   425  		p := &packages_model.Package{
   426  			OwnerID:    ownerID,
   427  			Type:       packageType,
   428  			Name:       name,
   429  			LowerName:  name,
   430  			IsInternal: true,
   431  		}
   432  		var err error
   433  		if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
   434  			if err != packages_model.ErrDuplicatePackage {
   435  				log.Error("Error inserting package: %v", err)
   436  				return err
   437  			}
   438  		}
   439  
   440  		pv = &packages_model.PackageVersion{
   441  			PackageID:    p.ID,
   442  			CreatorID:    ownerID,
   443  			Version:      version,
   444  			LowerVersion: version,
   445  			IsInternal:   true,
   446  			MetadataJSON: "null",
   447  		}
   448  		if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
   449  			if err != packages_model.ErrDuplicatePackageVersion {
   450  				log.Error("Error inserting package version: %v", err)
   451  				return err
   452  			}
   453  		}
   454  
   455  		return nil
   456  	})
   457  }
   458  
   459  // RemovePackageVersionByNameAndVersion deletes a package version and all associated files
   460  func RemovePackageVersionByNameAndVersion(ctx context.Context, doer *user_model.User, pvi *PackageInfo) error {
   461  	pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
   462  	if err != nil {
   463  		return err
   464  	}
   465  
   466  	return RemovePackageVersion(ctx, doer, pv)
   467  }
   468  
   469  // RemovePackageVersion deletes the package version and all associated files
   470  func RemovePackageVersion(ctx context.Context, doer *user_model.User, pv *packages_model.PackageVersion) error {
   471  	dbCtx, committer, err := db.TxContext(ctx)
   472  	if err != nil {
   473  		return err
   474  	}
   475  	defer committer.Close()
   476  
   477  	pd, err := packages_model.GetPackageDescriptor(dbCtx, pv)
   478  	if err != nil {
   479  		return err
   480  	}
   481  
   482  	log.Trace("Deleting package: %v", pv.ID)
   483  
   484  	if err := DeletePackageVersionAndReferences(dbCtx, pv); err != nil {
   485  		return err
   486  	}
   487  
   488  	if err := committer.Commit(); err != nil {
   489  		return err
   490  	}
   491  
   492  	notify_service.PackageDelete(ctx, doer, pd)
   493  
   494  	return nil
   495  }
   496  
   497  // RemovePackageFileAndVersionIfUnreferenced deletes the package file and the version if there are no referenced files afterwards
   498  func RemovePackageFileAndVersionIfUnreferenced(ctx context.Context, doer *user_model.User, pf *packages_model.PackageFile) error {
   499  	var pd *packages_model.PackageDescriptor
   500  
   501  	if err := db.WithTx(ctx, func(ctx context.Context) error {
   502  		if err := DeletePackageFile(ctx, pf); err != nil {
   503  			return err
   504  		}
   505  
   506  		has, err := packages_model.HasVersionFileReferences(ctx, pf.VersionID)
   507  		if err != nil {
   508  			return err
   509  		}
   510  		if !has {
   511  			pv, err := packages_model.GetVersionByID(ctx, pf.VersionID)
   512  			if err != nil {
   513  				return err
   514  			}
   515  
   516  			pd, err = packages_model.GetPackageDescriptor(ctx, pv)
   517  			if err != nil {
   518  				return err
   519  			}
   520  
   521  			if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
   522  				return err
   523  			}
   524  		}
   525  
   526  		return nil
   527  	}); err != nil {
   528  		return err
   529  	}
   530  
   531  	if pd != nil {
   532  		notify_service.PackageDelete(ctx, doer, pd)
   533  	}
   534  
   535  	return nil
   536  }
   537  
   538  // DeletePackageVersionAndReferences deletes the package version and its properties and files
   539  func DeletePackageVersionAndReferences(ctx context.Context, pv *packages_model.PackageVersion) error {
   540  	if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeVersion, pv.ID); err != nil {
   541  		return err
   542  	}
   543  
   544  	pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
   545  	if err != nil {
   546  		return err
   547  	}
   548  
   549  	for _, pf := range pfs {
   550  		if err := DeletePackageFile(ctx, pf); err != nil {
   551  			return err
   552  		}
   553  	}
   554  
   555  	return packages_model.DeleteVersionByID(ctx, pv.ID)
   556  }
   557  
   558  // DeletePackageFile deletes the package file and its properties
   559  func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) error {
   560  	if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
   561  		return err
   562  	}
   563  	return packages_model.DeleteFileByID(ctx, pf.ID)
   564  }
   565  
   566  // GetFileStreamByPackageNameAndVersion returns the content of the specific package file
   567  func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
   568  	log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
   569  
   570  	pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
   571  	if err != nil {
   572  		if err == packages_model.ErrPackageNotExist {
   573  			return nil, nil, nil, err
   574  		}
   575  		log.Error("Error getting package: %v", err)
   576  		return nil, nil, nil, err
   577  	}
   578  
   579  	return GetFileStreamByPackageVersion(ctx, pv, pfi)
   580  }
   581  
   582  // GetFileStreamByPackageVersion returns the content of the specific package file
   583  func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
   584  	pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
   585  	if err != nil {
   586  		return nil, nil, nil, err
   587  	}
   588  
   589  	return GetPackageFileStream(ctx, pf)
   590  }
   591  
   592  // GetPackageFileStream returns the content of the specific package file
   593  func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
   594  	pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
   595  	if err != nil {
   596  		return nil, nil, nil, err
   597  	}
   598  
   599  	return GetPackageBlobStream(ctx, pf, pb)
   600  }
   601  
   602  // GetPackageBlobStream returns the content of the specific package blob
   603  // If the storage supports direct serving and it's enabled, only the direct serving url is returned.
   604  func GetPackageBlobStream(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
   605  	key := packages_module.BlobHash256Key(pb.HashSHA256)
   606  
   607  	cs := packages_module.NewContentStore()
   608  
   609  	var s io.ReadSeekCloser
   610  	var u *url.URL
   611  	var err error
   612  
   613  	if cs.ShouldServeDirect() {
   614  		u, err = cs.GetServeDirectURL(key, pf.Name)
   615  		if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
   616  			log.Error("Error getting serve direct url: %v", err)
   617  		}
   618  	}
   619  	if u == nil {
   620  		s, err = cs.Get(key)
   621  	}
   622  
   623  	if err == nil {
   624  		if pf.IsLead {
   625  			if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
   626  				log.Error("Error incrementing download counter: %v", err)
   627  			}
   628  		}
   629  	}
   630  	return s, u, pf, err
   631  }
   632  
   633  // RemoveAllPackages for User
   634  func RemoveAllPackages(ctx context.Context, userID int64) (int, error) {
   635  	count := 0
   636  	for {
   637  		pkgVersions, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
   638  			Paginator: &db.ListOptions{
   639  				PageSize: repo_model.RepositoryListDefaultPageSize,
   640  				Page:     1,
   641  			},
   642  			OwnerID:    userID,
   643  			IsInternal: util.OptionalBoolNone,
   644  		})
   645  		if err != nil {
   646  			return count, fmt.Errorf("GetOwnedPackages[%d]: %w", userID, err)
   647  		}
   648  		if len(pkgVersions) == 0 {
   649  			break
   650  		}
   651  		for _, pv := range pkgVersions {
   652  			if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
   653  				return count, fmt.Errorf("unable to delete package %d:%s[%d]. Error: %w", pv.PackageID, pv.Version, pv.ID, err)
   654  			}
   655  			count++
   656  		}
   657  	}
   658  	return count, nil
   659  }