summaryrefslogtreecommitdiff
path: root/src/pkg/os/file_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/os/file_windows.go')
-rw-r--r--src/pkg/os/file_windows.go159
1 files changed, 104 insertions, 55 deletions
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index a3f5b4459..7d39fdd2c 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -5,13 +5,23 @@
package os
import (
+ "io"
"runtime"
"sync"
"syscall"
+ "unicode/utf16"
)
// File represents an open file descriptor.
type File struct {
+ *file
+}
+
+// file is the real representation of *File.
+// The extra level of indirection ensures that no clients of os
+// can overwrite this data, which could cause the finalizer
+// to close the wrong file descriptor.
+type file struct {
fd syscall.Handle
name string
dirinfo *dirInfo // nil unless directory being read
@@ -32,8 +42,8 @@ func NewFile(fd syscall.Handle, name string) *File {
if fd < 0 {
return nil
}
- f := &File{fd: fd, name: name}
- runtime.SetFinalizer(f, (*File).Close)
+ f := &File{&file{fd: fd, name: name}}
+ runtime.SetFinalizer(f.file, (*file).close)
return f
}
@@ -45,12 +55,12 @@ type dirInfo struct {
const DevNull = "NUL"
-func (file *File) isdir() bool { return file != nil && file.dirinfo != nil }
+func (f *file) isdir() bool { return f != nil && f.dirinfo != nil }
-func openFile(name string, flag int, perm uint32) (file *File, err Error) {
- r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
- if e != 0 {
- return nil, &PathError{"open", name, Errno(e)}
+func openFile(name string, flag int, perm FileMode) (file *File, err error) {
+ r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
+ if e != nil {
+ return nil, &PathError{"open", name, e}
}
// There's a race here with fork/exec, which we are
@@ -62,11 +72,11 @@ func openFile(name string, flag int, perm uint32) (file *File, err Error) {
return NewFile(r, name), nil
}
-func openDir(name string) (file *File, err Error) {
+func openDir(name string) (file *File, err error) {
d := new(dirInfo)
r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data)
- if e != 0 {
- return nil, &PathError{"open", name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"open", name, e}
}
f := NewFile(r, name)
f.dirinfo = d
@@ -77,8 +87,11 @@ func openDir(name string) (file *File, err Error) {
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
-// It returns the File and an Error, if any.
-func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
+// It returns the File and an error, if any.
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
+ if name == "" {
+ return nil, &PathError{"open", name, syscall.ENOENT}
+ }
// TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
r, e := openDir(name)
if e == nil {
@@ -96,20 +109,24 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
}
// Close closes the File, rendering it unusable for I/O.
-// It returns an Error, if any.
-func (file *File) Close() Error {
+// It returns an error, if any.
+func (file *File) Close() error {
+ return file.file.close()
+}
+
+func (file *file) close() error {
if file == nil || file.fd < 0 {
return EINVAL
}
- var e int
+ var e error
if file.isdir() {
e = syscall.FindClose(syscall.Handle(file.fd))
} else {
e = syscall.CloseHandle(syscall.Handle(file.fd))
}
- var err Error
- if e != 0 {
- err = &PathError{"close", file.name, Errno(e)}
+ var err error
+ if e != nil {
+ err = &PathError{"close", file.name, e}
}
file.fd = syscall.InvalidHandle // so it can't be closed again
@@ -118,22 +135,7 @@ func (file *File) Close() Error {
return err
}
-// Readdir reads the contents of the directory associated with file and
-// returns an array of up to n FileInfo structures, as would be returned
-// by Lstat, in directory order. Subsequent calls on the same file will yield
-// further FileInfos.
-//
-// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
-// Readdir returns an empty slice, it will return a non-nil error
-// explaining why. At the end of a directory, the error is os.EOF.
-//
-// If n <= 0, Readdir returns all the FileInfo from the directory in
-// a single slice. In this case, if Readdir succeeds (reads all
-// the way to the end of the directory), it returns the slice and a
-// nil os.Error. If it encounters an error before the end of the
-// directory, Readdir returns the FileInfo read until that point
-// and a non-nil error.
-func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
+func (file *File) readdir(n int) (fi []FileInfo, err error) {
if file == nil || file.fd < 0 {
return nil, EINVAL
}
@@ -151,11 +153,11 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
for n != 0 {
if file.dirinfo.needdata {
e := syscall.FindNextFile(syscall.Handle(file.fd), d)
- if e != 0 {
+ if e != nil {
if e == syscall.ERROR_NO_MORE_FILES {
break
} else {
- err = &PathError{"FindNextFile", file.name, Errno(e)}
+ err = &PathError{"FindNextFile", file.name, e}
if !wantAll {
fi = nil
}
@@ -163,24 +165,24 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
}
}
}
- var f FileInfo
- setFileInfo(&f, string(syscall.UTF16ToString(d.FileName[0:])), d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime)
file.dirinfo.needdata = true
- if f.Name == "." || f.Name == ".." { // Useless names
+ name := string(syscall.UTF16ToString(d.FileName[0:]))
+ if name == "." || name == ".." { // Useless names
continue
}
+ f := toFileInfo(name, d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime)
n--
fi = append(fi, f)
}
if !wantAll && len(fi) == 0 {
- return fi, EOF
+ return fi, io.EOF
}
return fi, nil
}
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
-func (f *File) read(b []byte) (n int, err int) {
+func (f *File) read(b []byte) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
return syscall.Read(f.fd, b)
@@ -189,11 +191,11 @@ func (f *File) read(b []byte) (n int, err int) {
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to 0.
-func (f *File) pread(b []byte, off int64) (n int, err int) {
+func (f *File) pread(b []byte, off int64) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
curoffset, e := syscall.Seek(f.fd, 0, 1)
- if e != 0 {
+ if e != nil {
return 0, e
}
defer syscall.Seek(f.fd, curoffset, 0)
@@ -203,15 +205,15 @@ func (f *File) pread(b []byte, off int64) (n int, err int) {
}
var done uint32
e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o)
- if e != 0 {
+ if e != nil {
return 0, e
}
- return int(done), 0
+ return int(done), nil
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
-func (f *File) write(b []byte) (n int, err int) {
+func (f *File) write(b []byte) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
return syscall.Write(f.fd, b)
@@ -219,11 +221,11 @@ func (f *File) write(b []byte) (n int, err int) {
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
-func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+func (f *File) pwrite(b []byte, off int64) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
curoffset, e := syscall.Seek(f.fd, 0, 1)
- if e != 0 {
+ if e != nil {
return 0, e
}
defer syscall.Seek(f.fd, curoffset, 0)
@@ -233,17 +235,17 @@ func (f *File) pwrite(b []byte, off int64) (n int, err int) {
}
var done uint32
e = syscall.WriteFile(syscall.Handle(f.fd), b, &done, &o)
- if e != 0 {
+ if e != nil {
return 0, e
}
- return int(done), 0
+ return int(done), nil
}
// seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
-func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+func (f *File) seek(offset int64, whence int) (ret int64, err error) {
f.l.Lock()
defer f.l.Unlock()
return syscall.Seek(f.fd, offset, whence)
@@ -251,7 +253,7 @@ func (f *File) seek(offset int64, whence int) (ret int64, err int) {
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
-func Truncate(name string, size int64) Error {
+func Truncate(name string, size int64) error {
f, e := OpenFile(name, O_WRONLY|O_CREATE, 0666)
if e != nil {
return e
@@ -264,15 +266,44 @@ func Truncate(name string, size int64) Error {
return nil
}
+// Remove removes the named file or directory.
+func Remove(name string) error {
+ p := &syscall.StringToUTF16(name)[0]
+
+ // Go file interface forces us to know whether
+ // name is a file or directory. Try both.
+ e := syscall.DeleteFile(p)
+ if e == nil {
+ return nil
+ }
+ e1 := syscall.RemoveDirectory(p)
+ if e1 == nil {
+ return nil
+ }
+
+ // Both failed: figure out which error to return.
+ if e1 != e {
+ a, e2 := syscall.GetFileAttributes(p)
+ if e2 != nil {
+ e = e2
+ } else {
+ if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
+ e = e1
+ }
+ }
+ }
+ return &PathError{"remove", name, e}
+}
+
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
-// It returns the files and an Error, if any.
-func Pipe() (r *File, w *File, err Error) {
+// It returns the files and an error, if any.
+func Pipe() (r *File, w *File, err error) {
var p [2]syscall.Handle
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
- if iserror(e) {
+ if e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
@@ -282,3 +313,21 @@ func Pipe() (r *File, w *File, err Error) {
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ const pathSep = '\\'
+ dirw := make([]uint16, syscall.MAX_PATH)
+ n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ dirw = make([]uint16, n)
+ n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ n = 0
+ }
+ }
+ if n > 0 && dirw[n-1] == pathSep {
+ n--
+ }
+ return string(utf16.Decode(dirw[0:n]))
+}