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 }