/
file.go
161 lines (136 loc) · 3.51 KB
/
file.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright (c) 2017-2019 The Bitum developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package util
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"io"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
"github.com/bitum-project/politeia/politeiad/api/v1/mime"
)
// MimeFile returns the MIME type of a file.
func MimeFile(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close()
// We need up to 512 bytes
b := make([]byte, 512)
n, err := f.Read(b)
if err != nil {
return "", err
}
// Clip buffer to prevent detecting binary files.
return mime.DetectMimeType(b[:n]), nil
}
// DigestFile returns the SHA256 of a file.
func DigestFile(filename string) (string, error) {
b, err := DigestFileBytes(filename)
if err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
// DigestFileBytes returns the SHA256 of a file.
func DigestFileBytes(filename string) ([]byte, error) {
h := sha256.New()
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
if _, err = io.Copy(h, f); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
// Base64File returns the base64 content of a file.
func Base64File(filename string) (string, error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(b), nil
}
// LoadFile loads a file of disk and returns the MIME type, the sha256 digest
// and the payload encoded as base64. If any of the intermediary operations
// fail the function will return an error instead.
func LoadFile(filename string) (mimeType string, digest string, payload string, err error) {
var b []byte // file payload
b, err = ioutil.ReadFile(filename)
if err != nil {
return
}
// MIME
mimeType = mime.DetectMimeType(b)
// Digest
h := sha256.New()
h.Write(b)
digest = hex.EncodeToString(h.Sum(nil))
// Payload
payload = base64.StdEncoding.EncodeToString(b)
return
}
// FilesExists reports whether the named file or directory exists.
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
// CleanAndExpandPath expands environment variables and leading ~ in the
// passed path, cleans the result, and returns it.
func CleanAndExpandPath(path string) string {
// Nothing to do when no path is given.
if path == "" {
return path
}
// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
// %VARIABLE%, but the variables can still be expanded via POSIX-style
// $VARIABLE.
path = os.ExpandEnv(path)
if !strings.HasPrefix(path, "~") {
return filepath.Clean(path)
}
// Expand initial ~ to the current user's home directory, or ~otheruser
// to otheruser's home directory. On Windows, both forward and backward
// slashes can be used.
path = path[1:]
var pathSeparators string
if runtime.GOOS == "windows" {
pathSeparators = string(os.PathSeparator) + "/"
} else {
pathSeparators = string(os.PathSeparator)
}
userName := ""
if i := strings.IndexAny(path, pathSeparators); i != -1 {
userName = path[:i]
path = path[i:]
}
homeDir := ""
var u *user.User
var err error
if userName == "" {
u, err = user.Current()
} else {
u, err = user.Lookup(userName)
}
if err == nil {
homeDir = u.HomeDir
}
// Fallback to CWD if user lookup fails or user has no home directory.
if homeDir == "" {
homeDir = "."
}
return filepath.Join(homeDir, path)
}