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