2018-04-20 18:33:50 +08:00
package hashsum
import (
2019-06-17 16:34:30 +08:00
"context"
2018-04-20 18:33:50 +08:00
"fmt"
"os"
2019-07-29 01:47:38 +08:00
"github.com/rclone/rclone/cmd"
2020-12-18 20:45:58 +08:00
"github.com/rclone/rclone/fs"
2019-10-27 03:27:33 +08:00
"github.com/rclone/rclone/fs/config/flags"
2019-07-29 01:47:38 +08:00
"github.com/rclone/rclone/fs/hash"
"github.com/rclone/rclone/fs/operations"
2018-04-20 18:33:50 +08:00
"github.com/spf13/cobra"
2020-12-18 20:45:58 +08:00
"github.com/spf13/pflag"
2018-04-20 18:33:50 +08:00
)
2021-05-18 17:27:17 +08:00
// Global hashsum flags for reuse in hashsum, md5sum, sha1sum
2019-10-27 03:27:33 +08:00
var (
2020-12-18 20:45:58 +08:00
OutputBase64 = false
DownloadFlag = false
HashsumOutfile = ""
2021-07-07 23:34:16 +08:00
ChecksumFile = ""
2019-10-27 03:27:33 +08:00
)
2018-04-20 18:33:50 +08:00
func init ( ) {
cmd . Root . AddCommand ( commandDefinition )
2019-10-27 03:27:33 +08:00
cmdFlags := commandDefinition . Flags ( )
2021-11-03 07:34:20 +08:00
AddHashsumFlags ( cmdFlags )
2020-12-18 20:45:58 +08:00
}
2021-11-03 07:34:20 +08:00
// AddHashsumFlags is a convenience function to add the command flags OutputBase64 and DownloadFlag to hashsum, md5sum, sha1sum
func AddHashsumFlags ( cmdFlags * pflag . FlagSet ) {
2020-12-18 20:45:58 +08:00
flags . BoolVarP ( cmdFlags , & OutputBase64 , "base64" , "" , OutputBase64 , "Output base64 encoded hashsum" )
flags . StringVarP ( cmdFlags , & HashsumOutfile , "output-file" , "" , HashsumOutfile , "Output hashsums to a file rather than the terminal" )
2021-07-07 23:34:16 +08:00
flags . StringVarP ( cmdFlags , & ChecksumFile , "checkfile" , "C" , ChecksumFile , "Validate hashes against a given SUM file instead of printing them" )
2020-12-18 20:45:58 +08:00
flags . BoolVarP ( cmdFlags , & DownloadFlag , "download" , "" , DownloadFlag , "Download the file and hash it locally; if this flag is not specified, the hash is requested from the remote" )
}
// GetHashsumOutput opens and closes the output file when using the output-file flag
func GetHashsumOutput ( filename string ) ( out * os . File , close func ( ) , err error ) {
out , err = os . Create ( filename )
if err != nil {
2021-11-03 07:34:20 +08:00
err = fmt . Errorf ( "failed to open output file %v: %w" , filename , err )
2020-12-18 20:45:58 +08:00
return nil , nil , err
}
close = func ( ) {
err := out . Close ( )
if err != nil {
fs . Errorf ( nil , "Failed to close output file %v: %v" , filename , err )
}
}
return out , close , nil
2018-04-20 18:33:50 +08:00
}
2021-11-03 07:34:20 +08:00
// CreateFromStdinArg checks args and produces hashsum from standard input if it is requested
func CreateFromStdinArg ( ht hash . Type , args [ ] string , startArg int ) ( bool , error ) {
var stdinArg bool
if len ( args ) == startArg {
// Missing arg: Always read from stdin
stdinArg = true
} else if len ( args ) > startArg && args [ startArg ] == "-" {
// Special arg: Read from stdin only if there is data available
if fi , _ := os . Stdin . Stat ( ) ; fi . Mode ( ) & os . ModeCharDevice == 0 {
stdinArg = true
}
}
if ! stdinArg {
return false , nil
}
if HashsumOutfile == "" {
return true , operations . HashSumStream ( ht , OutputBase64 , os . Stdin , nil )
}
output , close , err := GetHashsumOutput ( HashsumOutfile )
if err != nil {
return true , err
}
defer close ( )
return true , operations . HashSumStream ( ht , OutputBase64 , os . Stdin , output )
}
2018-04-20 18:33:50 +08:00
var commandDefinition = & cobra . Command {
Use : "hashsum <hash> remote:path" ,
2020-05-19 19:02:44 +08:00
Short : ` Produces a hashsum file for all the objects in the path. ` ,
2018-04-20 18:33:50 +08:00
Long : `
Produces a hash file for all the objects in the path using the hash
named . The output is in the same format as the standard
md5sum / sha1sum tool .
2020-12-18 20:45:58 +08:00
By default , the hash is requested from the remote . If the hash is
not supported by the remote , no hash will be returned . With the
download flag , the file will be downloaded from the remote and
hashed locally enabling any hash for any remote .
2021-11-03 07:34:20 +08:00
This command can also hash data received on standard input ( stdin ) ,
by not passing a remote : path , or by passing a hyphen as remote : path
when there is data to read ( if not , the hypen will be treated literaly ,
as a relative path ) .
2020-12-18 20:45:58 +08:00
Run without a hash to see the list of all supported hashes , e . g .
2018-04-20 18:33:50 +08:00
$ rclone hashsum
2021-07-07 23:34:16 +08:00
` + hash.HelpString(4) + `
2018-04-20 18:33:50 +08:00
Then
$ rclone hashsum MD5 remote : path
2021-05-21 22:32:33 +08:00
2021-10-13 20:02:49 +08:00
Note that hash names are case insensitive and values are output in lower case .
2018-04-20 18:33:50 +08:00
` ,
RunE : func ( command * cobra . Command , args [ ] string ) error {
cmd . CheckArgs ( 0 , 2 , command , args )
if len ( args ) == 0 {
2021-07-07 23:34:16 +08:00
fmt . Print ( hash . HelpString ( 0 ) )
2018-04-20 18:33:50 +08:00
return nil
}
var ht hash . Type
err := ht . Set ( args [ 0 ] )
if err != nil {
2021-07-07 23:34:16 +08:00
fmt . Println ( hash . HelpString ( 0 ) )
2018-04-20 18:33:50 +08:00
return err
}
2021-11-03 07:34:20 +08:00
if found , err := CreateFromStdinArg ( ht , args , 1 ) ; found {
return err
}
2018-04-20 18:33:50 +08:00
fsrc := cmd . NewFsSrc ( args [ 1 : ] )
cmd . Run ( false , false , command , func ( ) error {
2021-07-07 23:34:16 +08:00
if ChecksumFile != "" {
fsum , sumFile := cmd . NewFsFile ( ChecksumFile )
return operations . CheckSum ( context . Background ( ) , fsrc , fsum , sumFile , ht , nil , DownloadFlag )
}
2020-12-18 20:45:58 +08:00
if HashsumOutfile == "" {
return operations . HashLister ( context . Background ( ) , ht , OutputBase64 , DownloadFlag , fsrc , nil )
}
output , close , err := GetHashsumOutput ( HashsumOutfile )
if err != nil {
return err
2019-10-27 03:27:33 +08:00
}
2020-12-18 20:45:58 +08:00
defer close ( )
return operations . HashLister ( context . Background ( ) , ht , OutputBase64 , DownloadFlag , fsrc , output )
2018-04-20 18:33:50 +08:00
} )
return nil
} ,
}