1
0
mirror of https://github.com/minio/mc.git synced 2025-07-30 07:23:03 +03:00

rm: Force removing an object when it is encrypted without key specified (#2700)

Currently, a single remove HEAD an object, but this latter can return
400 Bad Request when the object is encrypted and the user doesn't specify
any encryption key.

So when HEAD fail, this PR will use GET listing to find the object and
remove it if existent.

We can avoid calling HEAD in the first place and use only listing, but this
has some penality on the server.
This commit is contained in:
Anis Elleuch
2019-03-12 22:03:59 +01:00
committed by kannappanr
parent e684b48cfe
commit a498b9b3a2
5 changed files with 55 additions and 28 deletions

View File

@ -176,21 +176,20 @@ func checkRmSyntax(ctx *cli.Context, encKeyDB map[string][]prefixSSEPair) {
}
func removeSingle(url string, isIncomplete bool, isFake bool, olderThan, newerThan string, encKeyDB map[string][]prefixSSEPair) error {
targetAlias, targetURL, _ := mustExpandAlias(url)
clnt, pErr := newClientFromAlias(targetAlias, targetURL)
if pErr != nil {
errorIf(pErr.Trace(url), "Invalid argument `"+url+"`.")
return exitStatus(globalErrorExitStatus) // End of journey.
}
isFetchMeta := true
alias, _ := url2Alias(url)
sseKey := getSSE(url, encKeyDB[alias])
content, pErr := clnt.Stat(isIncomplete, isFetchMeta, sseKey)
isRecursive := false
contents, pErr := statURL(url, isIncomplete, isRecursive, encKeyDB)
if pErr != nil {
errorIf(pErr.Trace(url), "Failed to remove `"+url+"`.")
return exitStatus(globalErrorExitStatus)
}
if len(contents) == 0 {
errorIf(errDummy().Trace(url), "Failed to remove `"+url+"`. Target object is not found")
return exitStatus(globalErrorExitStatus)
}
content := contents[0]
// Skip objects older than older--than parameter if specified
if olderThan != "" && isOlder(content.Time, olderThan) {
return nil
@ -207,6 +206,13 @@ func removeSingle(url string, isIncomplete bool, isFake bool, olderThan, newerTh
})
if !isFake {
targetAlias, targetURL, _ := mustExpandAlias(url)
clnt, pErr := newClientFromAlias(targetAlias, targetURL)
if pErr != nil {
errorIf(pErr.Trace(url), "Invalid argument `"+url+"`.")
return exitStatus(globalErrorExitStatus) // End of journey.
}
contentCh := make(chan *clientContent, 1)
contentCh <- &clientContent{URL: *newClientURL(targetURL)}
close(contentCh)

View File

@ -121,12 +121,18 @@ func mainStat(ctx *cli.Context) error {
var cErr error
for _, targetURL := range args {
var clnt Client
clnt, err := newClient(targetURL)
fatalIf(err.Trace(targetURL), "Unable to initialize target `"+targetURL+"`.")
targetAlias, _, _ := mustExpandAlias(targetURL)
return doStat(clnt, isRecursive, targetAlias, targetURL, encKeyDB)
stats, err := statURL(targetURL, false, isRecursive, encKeyDB)
if err != nil {
fatalIf(err, "Unable to stat `"+targetURL+"`.")
}
for _, stat := range stats {
st := parseStat(stat)
if !globalJSON {
printStat(st)
} else {
console.Println(st.JSON())
}
}
}
return cErr

View File

@ -92,7 +92,7 @@ func (c statMessage) JSON() string {
}
// parseStat parses client Content container into statMessage struct.
func parseStat(targetAlias string, c *clientContent) statMessage {
func parseStat(c *clientContent) statMessage {
content := statMessage{}
content.Date = c.Time.Local()
// guess file type.
@ -112,8 +112,16 @@ func parseStat(targetAlias string, c *clientContent) statMessage {
return content
}
// doStat - list all entities inside a folder.
func doStat(clnt Client, isRecursive bool, targetAlias, targetURL string, encKeyDB map[string][]prefixSSEPair) error {
// statURL - simple or recursive listing
func statURL(targetURL string, isIncomplete, isRecursive bool, encKeyDB map[string][]prefixSSEPair) ([]*clientContent, *probe.Error) {
var stats []*clientContent
var clnt Client
clnt, err := newClient(targetURL)
if err != nil {
return nil, err
}
targetAlias, _, _ := mustExpandAlias(targetURL)
prefixPath := clnt.GetURL().Path
separator := string(clnt.GetURL().Separator)
@ -121,7 +129,6 @@ func doStat(clnt Client, isRecursive bool, targetAlias, targetURL string, encKey
prefixPath = prefixPath[:strings.LastIndex(prefixPath, separator)+1]
}
var cErr error
isIncomplete := false
for content := range clnt.List(isRecursive, isIncomplete, DirNone) {
if content.Err != nil {
switch content.Err.ToGoError().(type) {
@ -147,6 +154,11 @@ func doStat(clnt Client, isRecursive bool, targetAlias, targetURL string, encKey
continue
}
url := targetAlias + getKey(content)
if !isRecursive && url != targetURL {
return nil, errTargetNotFound(targetURL)
}
_, stat, err := url2Stat(url, true, encKeyDB)
if err != nil {
stat = content
@ -157,12 +169,8 @@ func doStat(clnt Client, isRecursive bool, targetAlias, targetURL string, encKey
// Trim prefix path from the content path.
contentURL = strings.TrimPrefix(contentURL, prefixPath)
stat.URL.Path = contentURL
st := parseStat(targetAlias, stat)
if !globalJSON {
printStat(st)
} else {
console.Println(st.JSON())
stats = append(stats, stat)
}
}
return cErr
return stats, probe.NewError(cErr)
}

View File

@ -40,7 +40,7 @@ func (s *TestSuite) TestParseStat(c *C) {
"play"},
}
for _, testCase := range testCases {
statMsg := parseStat(testCase.targetAlias, &testCase.content)
statMsg := parseStat(&testCase.content)
c.Assert(testCase.content.Metadata, DeepEquals, statMsg.Metadata)
c.Assert(testCase.content.EncryptionHeaders, DeepEquals, statMsg.EncryptionHeaders)
c.Assert(testCase.content.Size, Equals, statMsg.Size)

View File

@ -96,6 +96,13 @@ var errInvalidTarget = func(URL string) *probe.Error {
return probe.NewError(invalidTargetErr(errors.New(msg))).Untrace()
}
type targetNotFoundErr error
var errTargetNotFound = func(URL string) *probe.Error {
msg := "Target `" + URL + "` not found."
return probe.NewError(targetNotFoundErr(errors.New(msg))).Untrace()
}
type overwriteNotAllowedErr struct {
error
}