github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/os/file_windows.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os
     6  
     7  import (
     8  	"internal/syscall/windows"
     9  	"io"
    10  	"runtime"
    11  	"sync"
    12  	"syscall"
    13  	"unicode/utf16"
    14  	"unicode/utf8"
    15  	"unsafe"
    16  )
    17  
    18  // file is the real representation of *File.
    19  // The extra level of indirection ensures that no clients of os
    20  // can overwrite this data, which could cause the finalizer
    21  // to close the wrong file descriptor.
    22  type file struct {
    23  	fd      syscall.Handle
    24  	name    string
    25  	dirinfo *dirInfo   // nil unless directory being read
    26  	l       sync.Mutex // used to implement windows pread/pwrite
    27  
    28  	// only for console io
    29  	isConsole      bool
    30  	lastbits       []byte   // first few bytes of the last incomplete rune in last write
    31  	readuint16     []uint16 // buffer to hold uint16s obtained with ReadConsole
    32  	readbyte       []byte   // buffer to hold decoding of readuint16 from utf16 to utf8
    33  	readbyteOffset int      // readbyte[readOffset:] is yet to be consumed with file.Read
    34  }
    35  
    36  // Fd returns the Windows handle referencing the open file.
    37  // The handle is valid only until f.Close is called or f is garbage collected.
    38  func (file *File) Fd() uintptr {
    39  	if file == nil {
    40  		return uintptr(syscall.InvalidHandle)
    41  	}
    42  	return uintptr(file.fd)
    43  }
    44  
    45  // newFile returns a new File with the given file handle and name.
    46  // Unlike NewFile, it does not check that h is syscall.InvalidHandle.
    47  func newFile(h syscall.Handle, name string) *File {
    48  	f := &File{&file{fd: h, name: name}}
    49  	runtime.SetFinalizer(f.file, (*file).close)
    50  	return f
    51  }
    52  
    53  // newConsoleFile creates new File that will be used as console.
    54  func newConsoleFile(h syscall.Handle, name string) *File {
    55  	f := newFile(h, name)
    56  	f.isConsole = true
    57  	return f
    58  }
    59  
    60  // NewFile returns a new File with the given file descriptor and name.
    61  func NewFile(fd uintptr, name string) *File {
    62  	h := syscall.Handle(fd)
    63  	if h == syscall.InvalidHandle {
    64  		return nil
    65  	}
    66  	var m uint32
    67  	if syscall.GetConsoleMode(h, &m) == nil {
    68  		return newConsoleFile(h, name)
    69  	}
    70  	return newFile(h, name)
    71  }
    72  
    73  // Auxiliary information if the File describes a directory
    74  type dirInfo struct {
    75  	data     syscall.Win32finddata
    76  	needdata bool
    77  	path     string
    78  	isempty  bool // set if FindFirstFile returns ERROR_FILE_NOT_FOUND
    79  }
    80  
    81  func epipecheck(file *File, e error) {
    82  }
    83  
    84  const DevNull = "NUL"
    85  
    86  func (f *file) isdir() bool { return f != nil && f.dirinfo != nil }
    87  
    88  func openFile(name string, flag int, perm FileMode) (file *File, err error) {
    89  	r, e := syscall.Open(fixLongPath(name), flag|syscall.O_CLOEXEC, syscallMode(perm))
    90  	if e != nil {
    91  		return nil, e
    92  	}
    93  	return NewFile(uintptr(r), name), nil
    94  }
    95  
    96  func openDir(name string) (file *File, err error) {
    97  	var mask string
    98  
    99  	path := fixLongPath(name)
   100  
   101  	if len(path) == 2 && path[1] == ':' || (len(path) > 0 && path[len(path)-1] == '\\') { // it is a drive letter, like C:
   102  		mask = path + `*`
   103  	} else {
   104  		mask = path + `\*`
   105  	}
   106  	maskp, e := syscall.UTF16PtrFromString(mask)
   107  	if e != nil {
   108  		return nil, e
   109  	}
   110  	d := new(dirInfo)
   111  	r, e := syscall.FindFirstFile(maskp, &d.data)
   112  	if e != nil {
   113  		// FindFirstFile returns ERROR_FILE_NOT_FOUND when
   114  		// no matching files can be found. Then, if directory
   115  		// exists, we should proceed.
   116  		if e != syscall.ERROR_FILE_NOT_FOUND {
   117  			return nil, e
   118  		}
   119  		var fa syscall.Win32FileAttributeData
   120  		pathp, e := syscall.UTF16PtrFromString(path)
   121  		if e != nil {
   122  			return nil, e
   123  		}
   124  		e = syscall.GetFileAttributesEx(pathp, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
   125  		if e != nil {
   126  			return nil, e
   127  		}
   128  		if fa.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 {
   129  			return nil, e
   130  		}
   131  		d.isempty = true
   132  	}
   133  	d.path = path
   134  	if !isAbs(d.path) {
   135  		d.path, e = syscall.FullPath(d.path)
   136  		if e != nil {
   137  			return nil, e
   138  		}
   139  	}
   140  	f := newFile(r, name)
   141  	f.dirinfo = d
   142  	return f, nil
   143  }
   144  
   145  // OpenFile is the generalized open call; most users will use Open
   146  // or Create instead. It opens the named file with specified flag
   147  // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
   148  // methods on the returned File can be used for I/O.
   149  // If there is an error, it will be of type *PathError.
   150  func OpenFile(name string, flag int, perm FileMode) (*File, error) {
   151  	if name == "" {
   152  		return nil, &PathError{"open", name, syscall.ENOENT}
   153  	}
   154  	r, errf := openFile(name, flag, perm)
   155  	if errf == nil {
   156  		return r, nil
   157  	}
   158  	r, errd := openDir(name)
   159  	if errd == nil {
   160  		if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
   161  			r.Close()
   162  			return nil, &PathError{"open", name, syscall.EISDIR}
   163  		}
   164  		return r, nil
   165  	}
   166  	return nil, &PathError{"open", name, errf}
   167  }
   168  
   169  // Close closes the File, rendering it unusable for I/O.
   170  // It returns an error, if any.
   171  func (file *File) Close() error {
   172  	if file == nil {
   173  		return ErrInvalid
   174  	}
   175  	return file.file.close()
   176  }
   177  
   178  func (file *file) close() error {
   179  	if file == nil {
   180  		return syscall.EINVAL
   181  	}
   182  	if file.isdir() && file.dirinfo.isempty {
   183  		// "special" empty directories
   184  		return nil
   185  	}
   186  	if file.fd == syscall.InvalidHandle {
   187  		return syscall.EINVAL
   188  	}
   189  	var e error
   190  	if file.isdir() {
   191  		e = syscall.FindClose(file.fd)
   192  	} else {
   193  		e = syscall.CloseHandle(file.fd)
   194  	}
   195  	var err error
   196  	if e != nil {
   197  		err = &PathError{"close", file.name, e}
   198  	}
   199  	file.fd = badFd // so it can't be closed again
   200  
   201  	// no need for a finalizer anymore
   202  	runtime.SetFinalizer(file, nil)
   203  	return err
   204  }
   205  
   206  var readConsole = syscall.ReadConsole // changed for testing
   207  
   208  // readConsole reads utf16 characters from console File,
   209  // encodes them into utf8 and stores them in buffer b.
   210  // It returns the number of utf8 bytes read and an error, if any.
   211  func (f *File) readConsole(b []byte) (n int, err error) {
   212  	if len(b) == 0 {
   213  		return 0, nil
   214  	}
   215  
   216  	if f.readuint16 == nil {
   217  		// Note: syscall.ReadConsole fails for very large buffers.
   218  		// The limit is somewhere around (but not exactly) 16384.
   219  		// Stay well below.
   220  		f.readuint16 = make([]uint16, 0, 10000)
   221  		f.readbyte = make([]byte, 0, 4*cap(f.readuint16))
   222  	}
   223  
   224  	for f.readbyteOffset >= len(f.readbyte) {
   225  		n := cap(f.readuint16) - len(f.readuint16)
   226  		if n > len(b) {
   227  			n = len(b)
   228  		}
   229  		var nw uint32
   230  		err := readConsole(f.fd, &f.readuint16[:len(f.readuint16)+1][len(f.readuint16)], uint32(n), &nw, nil)
   231  		if err != nil {
   232  			return 0, err
   233  		}
   234  		uint16s := f.readuint16[:len(f.readuint16)+int(nw)]
   235  		f.readuint16 = f.readuint16[:0]
   236  		buf := f.readbyte[:0]
   237  		for i := 0; i < len(uint16s); i++ {
   238  			r := rune(uint16s[i])
   239  			if utf16.IsSurrogate(r) {
   240  				if i+1 == len(uint16s) {
   241  					if nw > 0 {
   242  						// Save half surrogate pair for next time.
   243  						f.readuint16 = f.readuint16[:1]
   244  						f.readuint16[0] = uint16(r)
   245  						break
   246  					}
   247  					r = utf8.RuneError
   248  				} else {
   249  					r = utf16.DecodeRune(r, rune(uint16s[i+1]))
   250  					if r != utf8.RuneError {
   251  						i++
   252  					}
   253  				}
   254  			}
   255  			n := utf8.EncodeRune(buf[len(buf):cap(buf)], r)
   256  			buf = buf[:len(buf)+n]
   257  		}
   258  		f.readbyte = buf
   259  		f.readbyteOffset = 0
   260  		if nw == 0 {
   261  			break
   262  		}
   263  	}
   264  
   265  	src := f.readbyte[f.readbyteOffset:]
   266  	var i int
   267  	for i = 0; i < len(src) && i < len(b); i++ {
   268  		x := src[i]
   269  		if x == 0x1A { // Ctrl-Z
   270  			if i == 0 {
   271  				f.readbyteOffset++
   272  			}
   273  			break
   274  		}
   275  		b[i] = x
   276  	}
   277  	f.readbyteOffset += i
   278  	return i, nil
   279  }
   280  
   281  // read reads up to len(b) bytes from the File.
   282  // It returns the number of bytes read and an error, if any.
   283  func (f *File) read(b []byte) (n int, err error) {
   284  	f.l.Lock()
   285  	defer f.l.Unlock()
   286  	if f.isConsole {
   287  		return f.readConsole(b)
   288  	}
   289  	return fixCount(syscall.Read(f.fd, b))
   290  }
   291  
   292  // pread reads len(b) bytes from the File starting at byte offset off.
   293  // It returns the number of bytes read and the error, if any.
   294  // EOF is signaled by a zero count with err set to 0.
   295  func (f *File) pread(b []byte, off int64) (n int, err error) {
   296  	f.l.Lock()
   297  	defer f.l.Unlock()
   298  	curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent)
   299  	if e != nil {
   300  		return 0, e
   301  	}
   302  	defer syscall.Seek(f.fd, curoffset, io.SeekStart)
   303  	o := syscall.Overlapped{
   304  		OffsetHigh: uint32(off >> 32),
   305  		Offset:     uint32(off),
   306  	}
   307  	var done uint32
   308  	e = syscall.ReadFile(f.fd, b, &done, &o)
   309  	if e != nil {
   310  		if e == syscall.ERROR_HANDLE_EOF {
   311  			// end of file
   312  			return 0, nil
   313  		}
   314  		return 0, e
   315  	}
   316  	return int(done), nil
   317  }
   318  
   319  // writeConsole writes len(b) bytes to the console File.
   320  // It returns the number of bytes written and an error, if any.
   321  func (f *File) writeConsole(b []byte) (n int, err error) {
   322  	n = len(b)
   323  	runes := make([]rune, 0, 256)
   324  	if len(f.lastbits) > 0 {
   325  		b = append(f.lastbits, b...)
   326  		f.lastbits = nil
   327  
   328  	}
   329  	for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
   330  		r, l := utf8.DecodeRune(b)
   331  		runes = append(runes, r)
   332  		b = b[l:]
   333  	}
   334  	if len(b) > 0 {
   335  		f.lastbits = make([]byte, len(b))
   336  		copy(f.lastbits, b)
   337  	}
   338  	// syscall.WriteConsole seems to fail, if given large buffer.
   339  	// So limit the buffer to 16000 characters. This number was
   340  	// discovered by experimenting with syscall.WriteConsole.
   341  	const maxWrite = 16000
   342  	for len(runes) > 0 {
   343  		m := len(runes)
   344  		if m > maxWrite {
   345  			m = maxWrite
   346  		}
   347  		chunk := runes[:m]
   348  		runes = runes[m:]
   349  		uint16s := utf16.Encode(chunk)
   350  		for len(uint16s) > 0 {
   351  			var written uint32
   352  			err = syscall.WriteConsole(f.fd, &uint16s[0], uint32(len(uint16s)), &written, nil)
   353  			if err != nil {
   354  				return 0, nil
   355  			}
   356  			uint16s = uint16s[written:]
   357  		}
   358  	}
   359  	return n, nil
   360  }
   361  
   362  // write writes len(b) bytes to the File.
   363  // It returns the number of bytes written and an error, if any.
   364  func (f *File) write(b []byte) (n int, err error) {
   365  	f.l.Lock()
   366  	defer f.l.Unlock()
   367  	if f.isConsole {
   368  		return f.writeConsole(b)
   369  	}
   370  	return fixCount(syscall.Write(f.fd, b))
   371  }
   372  
   373  // pwrite writes len(b) bytes to the File starting at byte offset off.
   374  // It returns the number of bytes written and an error, if any.
   375  func (f *File) pwrite(b []byte, off int64) (n int, err error) {
   376  	f.l.Lock()
   377  	defer f.l.Unlock()
   378  	curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent)
   379  	if e != nil {
   380  		return 0, e
   381  	}
   382  	defer syscall.Seek(f.fd, curoffset, io.SeekStart)
   383  	o := syscall.Overlapped{
   384  		OffsetHigh: uint32(off >> 32),
   385  		Offset:     uint32(off),
   386  	}
   387  	var done uint32
   388  	e = syscall.WriteFile(f.fd, b, &done, &o)
   389  	if e != nil {
   390  		return 0, e
   391  	}
   392  	return int(done), nil
   393  }
   394  
   395  // seek sets the offset for the next Read or Write on file to offset, interpreted
   396  // according to whence: 0 means relative to the origin of the file, 1 means
   397  // relative to the current offset, and 2 means relative to the end.
   398  // It returns the new offset and an error, if any.
   399  func (f *File) seek(offset int64, whence int) (ret int64, err error) {
   400  	f.l.Lock()
   401  	defer f.l.Unlock()
   402  	return syscall.Seek(f.fd, offset, whence)
   403  }
   404  
   405  // Truncate changes the size of the named file.
   406  // If the file is a symbolic link, it changes the size of the link's target.
   407  func Truncate(name string, size int64) error {
   408  	f, e := OpenFile(name, O_WRONLY|O_CREATE, 0666)
   409  	if e != nil {
   410  		return e
   411  	}
   412  	defer f.Close()
   413  	e1 := f.Truncate(size)
   414  	if e1 != nil {
   415  		return e1
   416  	}
   417  	return nil
   418  }
   419  
   420  // Remove removes the named file or directory.
   421  // If there is an error, it will be of type *PathError.
   422  func Remove(name string) error {
   423  	p, e := syscall.UTF16PtrFromString(fixLongPath(name))
   424  	if e != nil {
   425  		return &PathError{"remove", name, e}
   426  	}
   427  
   428  	// Go file interface forces us to know whether
   429  	// name is a file or directory. Try both.
   430  	e = syscall.DeleteFile(p)
   431  	if e == nil {
   432  		return nil
   433  	}
   434  	e1 := syscall.RemoveDirectory(p)
   435  	if e1 == nil {
   436  		return nil
   437  	}
   438  
   439  	// Both failed: figure out which error to return.
   440  	if e1 != e {
   441  		a, e2 := syscall.GetFileAttributes(p)
   442  		if e2 != nil {
   443  			e = e2
   444  		} else {
   445  			if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
   446  				e = e1
   447  			} else if a&syscall.FILE_ATTRIBUTE_READONLY != 0 {
   448  				if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil {
   449  					if e = syscall.DeleteFile(p); e == nil {
   450  						return nil
   451  					}
   452  				}
   453  			}
   454  		}
   455  	}
   456  	return &PathError{"remove", name, e}
   457  }
   458  
   459  func rename(oldname, newname string) error {
   460  	e := windows.Rename(fixLongPath(oldname), fixLongPath(newname))
   461  	if e != nil {
   462  		return &LinkError{"rename", oldname, newname, e}
   463  	}
   464  	return nil
   465  }
   466  
   467  // Pipe returns a connected pair of Files; reads from r return bytes written to w.
   468  // It returns the files and an error, if any.
   469  func Pipe() (r *File, w *File, err error) {
   470  	var p [2]syscall.Handle
   471  
   472  	// See ../syscall/exec.go for description of lock.
   473  	syscall.ForkLock.RLock()
   474  	e := syscall.Pipe(p[0:])
   475  	if e != nil {
   476  		syscall.ForkLock.RUnlock()
   477  		return nil, nil, NewSyscallError("pipe", e)
   478  	}
   479  	syscall.CloseOnExec(p[0])
   480  	syscall.CloseOnExec(p[1])
   481  	syscall.ForkLock.RUnlock()
   482  
   483  	return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
   484  }
   485  
   486  // TempDir returns the default directory to use for temporary files.
   487  func TempDir() string {
   488  	n := uint32(syscall.MAX_PATH)
   489  	for {
   490  		b := make([]uint16, n)
   491  		n, _ = syscall.GetTempPath(uint32(len(b)), &b[0])
   492  		if n > uint32(len(b)) {
   493  			continue
   494  		}
   495  		if n > 0 && b[n-1] == '\\' {
   496  			n--
   497  		}
   498  		return string(utf16.Decode(b[:n]))
   499  	}
   500  }
   501  
   502  // Link creates newname as a hard link to the oldname file.
   503  // If there is an error, it will be of type *LinkError.
   504  func Link(oldname, newname string) error {
   505  	n, err := syscall.UTF16PtrFromString(fixLongPath(newname))
   506  	if err != nil {
   507  		return &LinkError{"link", oldname, newname, err}
   508  	}
   509  	o, err := syscall.UTF16PtrFromString(fixLongPath(oldname))
   510  	if err != nil {
   511  		return &LinkError{"link", oldname, newname, err}
   512  	}
   513  	err = syscall.CreateHardLink(n, o, 0)
   514  	if err != nil {
   515  		return &LinkError{"link", oldname, newname, err}
   516  	}
   517  	return nil
   518  }
   519  
   520  // Symlink creates newname as a symbolic link to oldname.
   521  // If there is an error, it will be of type *LinkError.
   522  func Symlink(oldname, newname string) error {
   523  	// CreateSymbolicLink is not supported before Windows Vista
   524  	if syscall.LoadCreateSymbolicLink() != nil {
   525  		return &LinkError{"symlink", oldname, newname, syscall.EWINDOWS}
   526  	}
   527  
   528  	// '/' does not work in link's content
   529  	oldname = fromSlash(oldname)
   530  
   531  	// need the exact location of the oldname when its relative to determine if its a directory
   532  	destpath := oldname
   533  	if !isAbs(oldname) {
   534  		destpath = dirname(newname) + `\` + oldname
   535  	}
   536  
   537  	fi, err := Lstat(destpath)
   538  	isdir := err == nil && fi.IsDir()
   539  
   540  	n, err := syscall.UTF16PtrFromString(fixLongPath(newname))
   541  	if err != nil {
   542  		return &LinkError{"symlink", oldname, newname, err}
   543  	}
   544  	o, err := syscall.UTF16PtrFromString(fixLongPath(oldname))
   545  	if err != nil {
   546  		return &LinkError{"symlink", oldname, newname, err}
   547  	}
   548  
   549  	var flags uint32
   550  	if isdir {
   551  		flags |= syscall.SYMBOLIC_LINK_FLAG_DIRECTORY
   552  	}
   553  	err = syscall.CreateSymbolicLink(n, o, flags)
   554  	if err != nil {
   555  		return &LinkError{"symlink", oldname, newname, err}
   556  	}
   557  	return nil
   558  }
   559  
   560  const badFd = syscall.InvalidHandle