github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/stat-main.go (about) 1 // Copyright (c) 2015-2022 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 "strings" 23 "time" 24 25 "github.com/fatih/color" 26 "github.com/minio/cli" 27 "github.com/minio/pkg/v2/console" 28 ) 29 30 // stat specific flags. 31 var ( 32 statFlags = []cli.Flag{ 33 cli.StringFlag{ 34 Name: "rewind", 35 Usage: "stat on older version(s)", 36 }, 37 cli.BoolFlag{ 38 Name: "versions", 39 Usage: "stat all versions", 40 }, 41 cli.StringFlag{ 42 Name: "version-id, vid", 43 Usage: "stat a specific object version", 44 }, 45 cli.BoolFlag{ 46 Name: "recursive, r", 47 Usage: "stat all objects recursively", 48 }, 49 } 50 ) 51 52 // show object metadata 53 var statCmd = cli.Command{ 54 Name: "stat", 55 Usage: "show object metadata", 56 Action: mainStat, 57 OnUsageError: onUsageError, 58 Before: setGlobalsFromContext, 59 Flags: append(append(statFlags, encCFlag), globalFlags...), 60 CustomHelpTemplate: `NAME: 61 {{.HelpName}} - {{.Usage}} 62 63 USAGE: 64 {{.HelpName}} [FLAGS] TARGET [TARGET ...] 65 66 FLAGS: 67 {{range .VisibleFlags}}{{.}} 68 {{end}} 69 70 EXAMPLES: 71 1. Stat all contents of mybucket on Amazon S3 cloud storage. 72 {{.Prompt}} {{.HelpName}} s3/mybucket/ 73 74 2. Stat all contents of mybucket on Amazon S3 cloud storage on Microsoft Windows. 75 {{.Prompt}} {{.HelpName}} s3\mybucket\ 76 77 3. Stat files recursively on a local filesystem on Microsoft Windows. 78 {{.Prompt}} {{.HelpName}} --recursive C:\Users\mydocuments\ 79 80 4. Stat encrypted files on Amazon S3 cloud storage. In case the encryption key contains non-printable character like tab, pass the 81 base64 encoded string as key. 82 {{.Prompt}} {{.HelpName}} --enc-c "s3/personal-document/=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA" s3/personal-document/2019-account_report.docx 83 84 5. Stat a specific object version. 85 {{.Prompt}} {{.HelpName}} --version-id "CL3sWgdSN2pNntSf6UnZAuh2kcu8E8si" s3/personal-docs/2018-account_report.docx 86 87 6. Stat all objects versions recursively created before 1st January 2020. 88 {{.Prompt}} {{.HelpName}} --versions --rewind 2020.01.01T00:00 s3/personal-docs/ 89 `, 90 } 91 92 // parseAndCheckStatSyntax - parse and validate all the passed arguments 93 func parseAndCheckStatSyntax(ctx context.Context, cliCtx *cli.Context, encKeyDB map[string][]prefixSSEPair) ([]string, bool, string, time.Time, bool) { 94 if !cliCtx.Args().Present() { 95 showCommandHelpAndExit(cliCtx, 1) // last argument is exit code 96 } 97 98 args := cliCtx.Args() 99 for _, arg := range args { 100 if strings.TrimSpace(arg) == "" { 101 fatalIf(errInvalidArgument().Trace(args...), "Unable to validate empty argument.") 102 } 103 } 104 105 recursive := cliCtx.Bool("recursive") 106 versionID := cliCtx.String("version-id") 107 withVersions := cliCtx.Bool("versions") 108 rewind := parseRewindFlag(cliCtx.String("rewind")) 109 110 // extract URLs. 111 URLs := cliCtx.Args() 112 113 if versionID != "" && len(args) > 1 { 114 fatalIf(errInvalidArgument().Trace(args...), "You cannot specify --version-id with multiple arguments.") 115 } 116 117 if versionID != "" && (recursive || withVersions || !rewind.IsZero()) { 118 fatalIf(errInvalidArgument().Trace(args...), "You cannot specify --version-id with either --rewind, --versions or --recursive.") 119 } 120 121 for _, url := range URLs { 122 _, _, err := url2Stat(ctx, url2StatOptions{urlStr: url, versionID: versionID, fileAttr: false, encKeyDB: encKeyDB, timeRef: rewind, isZip: false, ignoreBucketExistsCheck: false}) 123 if err != nil { 124 fatalIf(err.Trace(url), "Unable to stat `"+url+"`.") 125 } 126 } 127 128 return URLs, recursive, versionID, rewind, withVersions 129 } 130 131 // mainStat - is a handler for mc stat command 132 func mainStat(cliCtx *cli.Context) error { 133 ctx, cancelStat := context.WithCancel(globalContext) 134 defer cancelStat() 135 136 // Additional command specific theme customization. 137 console.SetColor("Name", color.New(color.Bold, color.FgCyan)) 138 console.SetColor("Date", color.New(color.FgWhite)) 139 console.SetColor("Size", color.New(color.FgWhite)) 140 console.SetColor("ETag", color.New(color.FgWhite)) 141 console.SetColor("Metadata", color.New(color.FgWhite)) 142 // theme specific to stat bucket 143 console.SetColor("Key", color.New(color.FgCyan)) 144 console.SetColor("Value", color.New(color.FgYellow)) 145 console.SetColor("Unset", color.New(color.FgRed)) 146 console.SetColor("Set", color.New(color.FgGreen)) 147 148 console.SetColor("Title", color.New(color.Bold, color.FgBlue)) 149 console.SetColor("Count", color.New(color.FgGreen)) 150 151 // Parse encryption keys per command. 152 encKeyDB, err := validateAndCreateEncryptionKeys(cliCtx) 153 fatalIf(err, "Unable to parse encryption keys.") 154 155 // check 'stat' cli arguments. 156 args, isRecursive, versionID, rewind, withVersions := parseAndCheckStatSyntax(ctx, cliCtx, encKeyDB) 157 // mimic operating system tool behavior. 158 if len(args) == 0 { 159 args = []string{"."} 160 } 161 162 for _, targetURL := range args { 163 fatalIf(statURL(ctx, targetURL, versionID, rewind, withVersions, false, isRecursive, encKeyDB), "Unable to stat `"+targetURL+"`.") 164 } 165 166 return nil 167 }