-
Notifications
You must be signed in to change notification settings - Fork 26
/
file.go
180 lines (161 loc) · 6.37 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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright (c) 2014-2017 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the license is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gowin32
import (
"strings"
"github.com/winlabs/gowin32/wrappers"
"os"
"syscall"
)
type FileShareMode uint32
const (
FileShareExclusive FileShareMode = 0
FileShareRead FileShareMode = wrappers.FILE_SHARE_READ
FileShareWrite FileShareMode = wrappers.FILE_SHARE_WRITE
FileShareDelete FileShareMode = wrappers.FILE_SHARE_DELETE
)
type FileCreationDisposition uint32
const (
FileCreateNew FileCreationDisposition = wrappers.CREATE_NEW
FileCreateAlways FileCreationDisposition = wrappers.CREATE_ALWAYS
FileOpenExisting FileCreationDisposition = wrappers.OPEN_EXISTING
FileOpenAlways FileCreationDisposition = wrappers.OPEN_ALWAYS
FileTruncateExisting FileCreationDisposition = wrappers.TRUNCATE_EXISTING
)
type FileAttributes uint32
const (
FileAttributeReadOnly FileAttributes = wrappers.FILE_ATTRIBUTE_READONLY
FileAttributeHidden FileAttributes = wrappers.FILE_ATTRIBUTE_HIDDEN
FileAttributeSystem FileAttributes = wrappers.FILE_ATTRIBUTE_SYSTEM
FileAttributeDirectory FileAttributes = wrappers.FILE_ATTRIBUTE_DIRECTORY
FileAttributeArchive FileAttributes = wrappers.FILE_ATTRIBUTE_ARCHIVE
FileAttributeDevice FileAttributes = wrappers.FILE_ATTRIBUTE_DEVICE
FileAttributeNormal FileAttributes = wrappers.FILE_ATTRIBUTE_NORMAL
FileAttributeTemporary FileAttributes = wrappers.FILE_ATTRIBUTE_TEMPORARY
FileAttributeSparseFile FileAttributes = wrappers.FILE_ATTRIBUTE_SPARSE_FILE
FileAttributeReparsePoint FileAttributes = wrappers.FILE_ATTRIBUTE_REPARSE_POINT
FileAttributeCompressed FileAttributes = wrappers.FILE_ATTRIBUTE_COMPRESSED
FileAttributeOffline FileAttributes = wrappers.FILE_ATTRIBUTE_OFFLINE
FileAttributeNotContentIndexed FileAttributes = wrappers.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
FileAttributeEncrypted FileAttributes = wrappers.FILE_ATTRIBUTE_ENCRYPTED
FileAttributeVirtual FileAttributes = wrappers.FILE_ATTRIBUTE_VIRTUAL
)
type FileFlags uint32
const (
FileFlagWriteThrough FileFlags = wrappers.FILE_FLAG_WRITE_THROUGH
FileFlagOverlapped FileFlags = wrappers.FILE_FLAG_OVERLAPPED
FileFlagNoBuffering FileFlags = wrappers.FILE_FLAG_NO_BUFFERING
FileFlagRandomAccess FileFlags = wrappers.FILE_FLAG_RANDOM_ACCESS
FileFlagSequentialScan FileFlags = wrappers.FILE_FLAG_SEQUENTIAL_SCAN
FileFlagDeleteOnClose FileFlags = wrappers.FILE_FLAG_DELETE_ON_CLOSE
FileFlagBackupSemantics FileFlags = wrappers.FILE_FLAG_BACKUP_SEMANTICS
FileFlagPOSIXSemantics FileFlags = wrappers.FILE_FLAG_POSIX_SEMANTICS
FileFlagOpenReparsePoint FileFlags = wrappers.FILE_FLAG_OPEN_REPARSE_POINT
FileFlagOpenNoRecall FileFlags = wrappers.FILE_FLAG_OPEN_NO_RECALL
FileFlagFirstPipeInstance FileFlags = wrappers.FILE_FLAG_FIRST_PIPE_INSTANCE
)
func OpenWindowsFile(fileName string, readWrite bool, shareMode FileShareMode, creationDisposition FileCreationDisposition, attributes FileAttributes, flags FileFlags) (*os.File, error) {
var accessMask uint32 = wrappers.GENERIC_READ
if readWrite {
accessMask |= wrappers.GENERIC_WRITE
}
file, err := wrappers.CreateFile(
syscall.StringToUTF16Ptr(fileName),
accessMask,
uint32(shareMode),
nil,
uint32(creationDisposition),
uint32(attributes)|uint32(flags),
0)
if err != nil {
return nil, NewWindowsError("CreateFile", err)
}
return os.NewFile(uintptr(file), fileName), nil
}
func ReadFileContents(fileName string) (string, error) {
file, err := wrappers.CreateFile(
syscall.StringToUTF16Ptr(fileName),
wrappers.GENERIC_READ,
wrappers.FILE_SHARE_READ|wrappers.FILE_SHARE_WRITE|wrappers.FILE_SHARE_DELETE,
nil,
wrappers.OPEN_EXISTING,
0,
0)
if err != nil {
return "", NewWindowsError("CreateFile", err)
}
defer wrappers.CloseHandle(file)
size, err := wrappers.GetFileSize(file, nil)
if err != nil {
return "", NewWindowsError("GetFileSize", err)
}
if size == 0 {
return "", nil
}
buf := make([]byte, size)
var bytesRead uint32
if err := wrappers.ReadFile(file, &buf[0], size, &bytesRead, nil); err != nil {
return "", NewWindowsError("ReadFile", err)
}
return string(buf[0:bytesRead]), nil
}
func TouchFile(f *os.File) error {
var now wrappers.FILETIME
wrappers.GetSystemTimeAsFileTime(&now)
if err := wrappers.SetFileTime(syscall.Handle(f.Fd()), nil, &now, &now); err != nil {
return NewWindowsError("SetFileTime", err)
}
return nil
}
func GetFinalPathName(fileName string, openFlags uint32, finalPathFlags uint32) (result string, err error) {
if isVistaOrGreater, e := IsWindowsVistaOrGreater(); e != nil {
return "", NewWindowsError("IsWindowsVistaOrGreater", e)
} else if !isVistaOrGreater {
// Todo: resolve symlink target on Windows XP, 2003
return fileName, nil
}
file, e := wrappers.CreateFile(
syscall.StringToUTF16Ptr(fileName),
wrappers.GENERIC_READ,
wrappers.FILE_SHARE_READ,
nil,
wrappers.OPEN_EXISTING,
openFlags,
0)
if e != nil {
return "", NewWindowsError("CreateFile", e)
}
defer wrappers.CloseHandle(file)
buf := make([]uint16, wrappers.MAX_PATH)
if _, err = wrappers.GetFinalPathNameByHandle(file, &buf[0], wrappers.MAX_PATH, finalPathFlags); err != nil {
return "", NewWindowsError("GetFinalPathNameByHandle", err)
}
result = syscall.UTF16ToString(buf)
return result, err
}
// GetFinalPathNameAsDOSName returns symlik target in "DOS" format (c:\dir\name) or source fileName if fileName is normal,
// not symlinked file
func GetFinalPathNameAsDOSName(fileName string) (string, error) {
result, err := GetFinalPathName(fileName, wrappers.FILE_ATTRIBUTE_NORMAL|wrappers.FILE_FLAG_BACKUP_SEMANTICS, wrappers.VOLUME_NAME_DOS)
if err != nil {
return "", err
}
// GetFinalPathName can return path in the \?\ syntax
if strings.HasPrefix(result, "\\\\?\\") {
result = result[4:]
}
return result, nil
}