27
29
dirinfo *dirInfo // nil unless directory being read
28
nepipe int // number of consecutive EPIPE in Write
29
30
l sync.Mutex // used to implement windows pread/pwrite
32
// only for console io
34
lastbits []byte // first few bytes of the last incomplete rune in last write
35
readbuf []rune // input console buffer
32
38
// Fd returns the Windows handle referencing the open file.
37
43
return uintptr(file.fd)
46
// newFile returns a new File with the given file handle and name.
47
// Unlike NewFile, it does not check that h is syscall.InvalidHandle.
48
func newFile(h syscall.Handle, name string) *File {
49
f := &File{&file{fd: h, name: name}}
51
if syscall.GetConsoleMode(f.fd, &m) == nil {
54
runtime.SetFinalizer(f.file, (*file).close)
40
58
// NewFile returns a new File with the given file descriptor and name.
41
59
func NewFile(fd uintptr, name string) *File {
42
60
h := syscall.Handle(fd)
43
61
if h == syscall.InvalidHandle {
46
f := &File{&file{fd: h, name: name}}
47
runtime.SetFinalizer(f.file, (*file).close)
64
return newFile(h, name)
51
67
// Auxiliary information if the File describes a directory
62
82
func openFile(name string, flag int, perm FileMode) (file *File, err error) {
63
83
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
65
return nil, &PathError{"open", name, e}
68
// There's a race here with fork/exec, which we are
69
// content to live with. See ../syscall/exec.go
70
if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
71
syscall.CloseOnExec(r)
74
87
return NewFile(uintptr(r), name), nil
77
90
func openDir(name string) (file *File, err error) {
91
maskp, e := syscall.UTF16PtrFromString(name + `\*`)
79
r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data)
96
r, e := syscall.FindFirstFile(maskp, &d.data)
81
return nil, &PathError{"open", name, e}
98
// FindFirstFile returns ERROR_FILE_NOT_FOUND when
99
// no matching files can be found. Then, if directory
100
// exists, we should proceed.
101
if e != syscall.ERROR_FILE_NOT_FOUND {
104
var fa syscall.Win32FileAttributeData
105
namep, e := syscall.UTF16PtrFromString(name)
109
e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
113
if fa.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 {
84
119
if !isAbs(d.path) {
86
121
d.path = cwd + `\` + d.path
88
f := NewFile(uintptr(r), name)
123
f := newFile(r, name)
124
159
func (file *file) close() error {
125
if file == nil || file.fd == syscall.InvalidHandle {
161
return syscall.EINVAL
163
if file.isdir() && file.dirinfo.isempty {
164
// "special" empty directories
167
if file.fd == syscall.InvalidHandle {
126
168
return syscall.EINVAL
145
187
func (file *File) readdir(n int) (fi []FileInfo, err error) {
146
if file == nil || file.fd == syscall.InvalidHandle {
147
189
return nil, syscall.EINVAL
149
191
if !file.isdir() {
150
192
return nil, &PathError{"Readdir", file.name, syscall.ENOTDIR}
194
if !file.dirinfo.isempty && file.fd == syscall.InvalidHandle {
195
return nil, syscall.EINVAL
152
197
wantAll := n <= 0
158
203
fi = make([]FileInfo, 0, size) // Empty with room to grow.
159
204
d := &file.dirinfo.data
205
for n != 0 && !file.dirinfo.isempty {
161
206
if file.dirinfo.needdata {
162
207
e := syscall.FindNextFile(syscall.Handle(file.fd), d)
182
size: mkSize(d.FileSizeHigh, d.FileSizeLow),
183
modTime: mkModTime(d.LastWriteTime),
184
mode: mkMode(d.FileAttributes),
185
sys: mkSys(file.dirinfo.path+`\`+name, d.LastAccessTime, d.CreationTime),
227
sys: syscall.Win32FileAttributeData{
228
FileAttributes: d.FileAttributes,
229
CreationTime: d.CreationTime,
230
LastAccessTime: d.LastAccessTime,
231
LastWriteTime: d.LastWriteTime,
232
FileSizeHigh: d.FileSizeHigh,
233
FileSizeLow: d.FileSizeLow,
235
path: file.dirinfo.path + `\` + name,
188
238
fi = append(fi, f)
246
// readConsole reads utf16 characters from console File,
247
// encodes them into utf8 and stores them in buffer b.
248
// It returns the number of utf8 bytes read and an error, if any.
249
func (f *File) readConsole(b []byte) (n int, err error) {
253
if len(f.readbuf) == 0 {
254
// get more input data from os
255
wchars := make([]uint16, len(b))
261
err := syscall.ReadConsole(f.fd, p, uint32(len(wchars)), &nw, nil)
265
f.readbuf = utf16.Decode(wchars[:nw])
267
for i, r := range f.readbuf {
268
if utf8.RuneLen(r) > len(b) {
269
f.readbuf = f.readbuf[i:]
272
nr := utf8.EncodeRune(b, r)
196
280
// read reads up to len(b) bytes from the File.
197
281
// It returns the number of bytes read and an error, if any.
198
282
func (f *File) read(b []byte) (n int, err error) {
200
284
defer f.l.Unlock()
286
return f.readConsole(b)
201
288
return syscall.Read(f.fd, b)
224
311
return int(done), nil
314
// writeConsole writes len(b) bytes to the console File.
315
// It returns the number of bytes written and an error, if any.
316
func (f *File) writeConsole(b []byte) (n int, err error) {
318
runes := make([]rune, 0, 256)
319
if len(f.lastbits) > 0 {
320
b = append(f.lastbits, b...)
324
for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
325
r, l := utf8.DecodeRune(b)
326
runes = append(runes, r)
330
f.lastbits = make([]byte, len(b))
333
// syscall.WriteConsole seems to fail, if given large buffer.
334
// So limit the buffer to 16000 characters. This number was
335
// discovered by experimenting with syscall.WriteConsole.
336
const maxWrite = 16000
344
uint16s := utf16.Encode(chunk)
345
for len(uint16s) > 0 {
347
err = syscall.WriteConsole(f.fd, &uint16s[0], uint32(len(uint16s)), &written, nil)
351
uint16s = uint16s[written:]
227
357
// write writes len(b) bytes to the File.
228
358
// It returns the number of bytes written and an error, if any.
229
359
func (f *File) write(b []byte) (n int, err error) {
231
361
defer f.l.Unlock()
363
return f.writeConsole(b)
232
365
return syscall.Write(f.fd, b)
282
415
// Remove removes the named file or directory.
283
416
// If there is an error, it will be of type *PathError.
284
417
func Remove(name string) error {
285
p := &syscall.StringToUTF16(name)[0]
418
p, e := syscall.UTF16PtrFromString(name)
420
return &PathError{"remove", name, e}
287
423
// Go file interface forces us to know whether
288
424
// name is a file or directory. Try both.
289
e := syscall.DeleteFile(p)
425
e = syscall.DeleteFile(p)