github.com/decred/politeia@v1.4.0/util/file.go (about) 1 // Copyright (c) 2017-2019 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package util 6 7 import ( 8 "crypto/sha256" 9 "encoding/base64" 10 "encoding/hex" 11 "io" 12 "os" 13 "os/user" 14 "path/filepath" 15 "runtime" 16 "strings" 17 18 "github.com/decred/politeia/politeiad/api/v1/mime" 19 ) 20 21 // MimeFile returns the MIME type of a file. 22 func MimeFile(filename string) (string, error) { 23 f, err := os.Open(filename) 24 if err != nil { 25 return "", err 26 } 27 defer f.Close() 28 29 // We need up to 512 bytes 30 b := make([]byte, 512) 31 n, err := f.Read(b) 32 if err != nil { 33 return "", err 34 } 35 36 // Clip buffer to prevent detecting binary files. 37 return mime.DetectMimeType(b[:n]), nil 38 } 39 40 // DigestFile returns the SHA256 of a file. 41 func DigestFile(filename string) (string, error) { 42 b, err := DigestFileBytes(filename) 43 if err != nil { 44 return "", err 45 } 46 return hex.EncodeToString(b), nil 47 } 48 49 // DigestFileBytes returns the SHA256 of a file. 50 func DigestFileBytes(filename string) ([]byte, error) { 51 h := sha256.New() 52 f, err := os.Open(filename) 53 if err != nil { 54 return nil, err 55 } 56 defer f.Close() 57 if _, err = io.Copy(h, f); err != nil { 58 return nil, err 59 } 60 61 return h.Sum(nil), nil 62 } 63 64 // Base64File returns the base64 content of a file. 65 func Base64File(filename string) (string, error) { 66 b, err := os.ReadFile(filename) 67 if err != nil { 68 return "", err 69 } 70 71 return base64.StdEncoding.EncodeToString(b), nil 72 } 73 74 // LoadFile loads a file of disk and returns the MIME type, the sha256 digest 75 // and the payload encoded as base64. If any of the intermediary operations 76 // fail the function will return an error instead. 77 func LoadFile(filename string) (mimeType string, digest string, payload string, err error) { 78 var b []byte // file payload 79 b, err = os.ReadFile(filename) 80 if err != nil { 81 return 82 } 83 84 // MIME 85 mimeType = mime.DetectMimeType(b) 86 87 // Digest 88 h := sha256.New() 89 h.Write(b) 90 digest = hex.EncodeToString(h.Sum(nil)) 91 92 // Payload 93 payload = base64.StdEncoding.EncodeToString(b) 94 95 return 96 } 97 98 // LoadFile2 returns a file and its mime type. 99 func LoadFile2(filename string) (string, []byte, error) { 100 var b []byte // file payload 101 b, err := os.ReadFile(filename) 102 if err != nil { 103 return "", nil, err 104 } 105 106 return mime.DetectMimeType(b), b, nil 107 } 108 109 // FilesExists reports whether the named file or directory exists. 110 func FileExists(name string) bool { 111 if _, err := os.Stat(name); err != nil { 112 if os.IsNotExist(err) { 113 return false 114 } 115 } 116 return true 117 } 118 119 // CleanAndExpandPath expands environment variables and leading ~ in the 120 // passed path, cleans the result, and returns it. 121 func CleanAndExpandPath(path string) string { 122 // Nothing to do when no path is given. 123 if path == "" { 124 return path 125 } 126 127 // NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style 128 // %VARIABLE%, but the variables can still be expanded via POSIX-style 129 // $VARIABLE. 130 path = os.ExpandEnv(path) 131 132 if !strings.HasPrefix(path, "~") { 133 return filepath.Clean(path) 134 } 135 136 // Expand initial ~ to the current user's home directory, or ~otheruser 137 // to otheruser's home directory. On Windows, both forward and backward 138 // slashes can be used. 139 path = path[1:] 140 141 var pathSeparators string 142 if runtime.GOOS == "windows" { 143 pathSeparators = string(os.PathSeparator) + "/" 144 } else { 145 pathSeparators = string(os.PathSeparator) 146 } 147 148 userName := "" 149 if i := strings.IndexAny(path, pathSeparators); i != -1 { 150 userName = path[:i] 151 path = path[i:] 152 } 153 154 homeDir := "" 155 var u *user.User 156 var err error 157 if userName == "" { 158 u, err = user.Current() 159 } else { 160 u, err = user.Lookup(userName) 161 } 162 if err == nil { 163 homeDir = u.HomeDir 164 } 165 // Fallback to CWD if user lookup fails or user has no home directory. 166 if homeDir == "" { 167 homeDir = "." 168 } 169 170 return filepath.Join(homeDir, path) 171 }