/
cp-url-syntax.go
145 lines (127 loc) · 4.76 KB
/
cp-url-syntax.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* Minio Client (C) 2015 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"fmt"
"github.com/minio/cli"
"github.com/minio/mc/pkg/client"
)
func checkCopySyntax(ctx *cli.Context) {
if len(ctx.Args()) < 2 {
cli.ShowCommandHelpAndExit(ctx, "cp", 1) // last argument is exit code.
}
// extract URLs.
URLs := ctx.Args()
if len(URLs) < 2 {
fatalIf(errDummy().Trace(ctx.Args()...), fmt.Sprintf("Unable to parse source and target arguments."))
}
srcURLs := URLs[:len(URLs)-1]
tgtURL := URLs[len(URLs)-1]
isRecursive := ctx.Bool("recursive")
/****** Generic Invalid Rules *******/
// Check if bucket name is passed for URL type arguments.
url := client.NewURL(tgtURL)
if url.Host != "" {
// This check is for type URL.
if !isURLVirtualHostStyle(url.Host) {
if url.Path == string(url.Separator) {
fatalIf(errInvalidArgument().Trace(), fmt.Sprintf("Target ‘%s’ does not contain bucket name.", tgtURL))
}
}
}
// Guess CopyURLsType based on source and target URLs.
copyURLsType, err := guessCopyURLType(srcURLs, tgtURL, isRecursive)
if err != nil {
fatalIf(errInvalidArgument().Trace(), "Unable to guess the type of copy operation.")
}
switch copyURLsType {
case copyURLsTypeA: // File -> File.
checkCopySyntaxTypeA(srcURLs, tgtURL)
case copyURLsTypeB: // File -> Folder.
checkCopySyntaxTypeB(srcURLs, tgtURL)
case copyURLsTypeC: // Folder... -> Folder.
checkCopySyntaxTypeC(srcURLs, tgtURL, isRecursive)
case copyURLsTypeD: // File1...FileN -> Folder.
checkCopySyntaxTypeD(srcURLs, tgtURL)
default:
fatalIf(errInvalidArgument().Trace(), "Unable to guess the type of copy operation.")
}
}
// checkCopySyntaxTypeA verifies if the source and target are valid file arguments.
func checkCopySyntaxTypeA(srcURLs []string, tgtURL string) {
// Check source.
if len(srcURLs) != 1 {
fatalIf(errInvalidArgument().Trace(), "Invalid number of source arguments.")
}
srcURL := srcURLs[0]
_, srcContent, err := url2Stat(srcURL)
fatalIf(err.Trace(srcURL), "Unable to stat source ‘"+srcURL+"’.")
if !srcContent.Type.IsRegular() {
fatalIf(errInvalidArgument().Trace(), "Source ‘"+srcURL+"’ is not a file.")
}
}
// checkCopySyntaxTypeB verifies if the source is a valid file and target is a valid folder.
func checkCopySyntaxTypeB(srcURLs []string, tgtURL string) {
// Check source.
if len(srcURLs) != 1 {
fatalIf(errInvalidArgument().Trace(), "Invalid number of source arguments.")
}
srcURL := srcURLs[0]
_, srcContent, err := url2Stat(srcURL)
fatalIf(err.Trace(srcURL), "Unable to stat source ‘"+srcURL+"’.")
if !srcContent.Type.IsRegular() {
fatalIf(errInvalidArgument().Trace(srcURL), "Source ‘"+srcURL+"’ is not a file.")
}
// Check target.
if _, tgtContent, err := url2Stat(tgtURL); err == nil {
if !tgtContent.Type.IsDir() {
fatalIf(errInvalidArgument().Trace(tgtURL), "Target ‘"+tgtURL+"’ is not a folder.")
}
}
}
// checkCopySyntaxTypeC verifies if the source is a valid recursive dir and target is a valid folder.
func checkCopySyntaxTypeC(srcURLs []string, tgtURL string, isRecursive bool) {
// Check source.
if len(srcURLs) != 1 {
fatalIf(errInvalidArgument().Trace(), "Invalid number of source arguments.")
}
srcURL := srcURLs[0]
_, srcContent, err := url2Stat(srcURL)
// incomplete uploads are not necessary for copy operation, no need to verify for them.
isIncomplete := false
if err != nil && !isURLPrefixExists(srcURL, isIncomplete) {
fatalIf(err.Trace(srcURL), "Unable to stat source ‘"+srcURL+"’.")
}
if srcContent.Type.IsDir() && !isRecursive {
fatalIf(errInvalidArgument().Trace(srcURL), "To copy a folder requires --recursive option.")
}
// Check target.
if _, tgtContent, err := url2Stat(tgtURL); err == nil {
if !tgtContent.Type.IsDir() {
fatalIf(errInvalidArgument().Trace(tgtURL), "Target ‘"+tgtURL+"’ is not a folder.")
}
}
}
// checkCopySyntaxTypeD verifies if the source is a valid list of files and target is a valid folder.
func checkCopySyntaxTypeD(srcURLs []string, tgtURL string) {
// Source can be anything: file, dir, dir...
// Check target if it is a dir
if _, tgtContent, err := url2Stat(tgtURL); err == nil {
if !tgtContent.Type.IsDir() {
fatalIf(errInvalidArgument().Trace(tgtURL), "Target ‘"+tgtURL+"’ is not a folder.")
}
}
}