github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/get-url.go (about)

     1  // Copyright (c) 2015-2024 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  
    24  	"github.com/minio/mc/pkg/probe"
    25  	"github.com/minio/minio-go/v7"
    26  )
    27  
    28  // prepareGetURLs - prepares target and source clientURLs for copying.
    29  func prepareGetURLs(ctx context.Context, o prepareCopyURLsOpts) chan URLs {
    30  	copyURLsCh := make(chan URLs)
    31  	go func(o prepareCopyURLsOpts) {
    32  		defer close(copyURLsCh)
    33  		copyURLsContent, err := guessGetURLType(ctx, o)
    34  		if err != nil {
    35  			copyURLsCh <- URLs{Error: err}
    36  			return
    37  		}
    38  
    39  		switch copyURLsContent.copyType {
    40  		case copyURLsTypeA:
    41  			copyURLsCh <- prepareCopyURLsTypeA(ctx, *copyURLsContent, o)
    42  		case copyURLsTypeB:
    43  			copyURLsCh <- prepareCopyURLsTypeB(ctx, *copyURLsContent, o)
    44  		default:
    45  			copyURLsCh <- URLs{Error: errInvalidArgument().Trace(o.sourceURLs...)}
    46  		}
    47  	}(o)
    48  
    49  	finalCopyURLsCh := make(chan URLs)
    50  	go func() {
    51  		defer close(finalCopyURLsCh)
    52  		for cpURLs := range copyURLsCh {
    53  			if cpURLs.Error != nil {
    54  				finalCopyURLsCh <- cpURLs
    55  				continue
    56  			}
    57  			finalCopyURLsCh <- cpURLs
    58  		}
    59  	}()
    60  
    61  	return finalCopyURLsCh
    62  }
    63  
    64  // guessGetURLType guesses the type of clientURL. This approach all allows prepareURL
    65  // functions to accurately report failure causes.
    66  func guessGetURLType(ctx context.Context, o prepareCopyURLsOpts) (*copyURLsContent, *probe.Error) {
    67  	cc := new(copyURLsContent)
    68  
    69  	// Extract alias before fiddling with the clientURL.
    70  	cc.sourceURL = o.sourceURLs[0]
    71  	cc.sourceAlias, _, _ = mustExpandAlias(cc.sourceURL)
    72  	// Find alias and expanded clientURL.
    73  	cc.targetAlias, cc.targetURL, _ = mustExpandAlias(o.targetURL)
    74  
    75  	if len(o.sourceURLs) == 1 { // 1 Source, 1 Target
    76  		var err *probe.Error
    77  
    78  		client, err := newClient(cc.sourceURL)
    79  		if err != nil {
    80  			cc.copyType = copyURLsTypeInvalid
    81  			return cc, err
    82  		}
    83  		s3clnt, ok := client.(*S3Client)
    84  		if !ok {
    85  			return cc, probe.NewError(fmt.Errorf("Source is not s3."))
    86  		}
    87  		bucket, path := s3clnt.url2BucketAndObject()
    88  		if bucket == "" {
    89  			return cc, probe.NewError(fmt.Errorf("Please set bucket for s3 resource."))
    90  		}
    91  		if path == "" {
    92  			return cc, probe.NewError(fmt.Errorf("Please set a full path for s3 resource."))
    93  		}
    94  		cc.sourceContent = s3clnt.objectInfo2ClientContent(bucket, minio.ObjectInfo{
    95  			Key: path,
    96  		})
    97  
    98  		client, err = newClient(o.targetURL)
    99  		if err != nil {
   100  			cc.copyType = copyURLsTypeInvalid
   101  			return cc, err
   102  		}
   103  		_, ok = client.(*fsClient)
   104  		if !ok {
   105  			return cc, probe.NewError(fmt.Errorf("Target is not local filesystem."))
   106  		}
   107  
   108  		// If target is a folder, it is Type B.
   109  		var isDir bool
   110  		isDir, cc.targetContent = isAliasURLDir(ctx, o.targetURL, o.encKeyDB, o.timeRef, o.ignoreBucketExistsCheck)
   111  		if isDir {
   112  			cc.copyType = copyURLsTypeB
   113  			cc.sourceVersionID = cc.sourceContent.VersionID
   114  			return cc, nil
   115  		}
   116  
   117  		// else Type A.
   118  		cc.copyType = copyURLsTypeA
   119  		cc.sourceVersionID = cc.sourceContent.VersionID
   120  		return cc, nil
   121  	}
   122  
   123  	cc.copyType = copyURLsTypeInvalid
   124  	return cc, errInvalidArgument().Trace()
   125  }