Black Lives Matter. Support the Equal Justice Initiative.

Source file src/os/stat_windows.go

Documentation: os

     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  	"syscall"
    10  	"unsafe"
    11  )
    12  
    13  // Stat returns the FileInfo structure describing file.
    14  // If there is an error, it will be of type *PathError.
    15  func (file *File) Stat() (FileInfo, error) {
    16  	if file == nil {
    17  		return nil, ErrInvalid
    18  	}
    19  
    20  	if file.isdir() {
    21  		// I don't know any better way to do that for directory
    22  		return Stat(file.dirinfo.path)
    23  	}
    24  	if isWindowsNulName(file.name) {
    25  		return &devNullStat, nil
    26  	}
    27  
    28  	ft, err := file.pfd.GetFileType()
    29  	if err != nil {
    30  		return nil, &PathError{Op: "GetFileType", Path: file.name, Err: err}
    31  	}
    32  	switch ft {
    33  	case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
    34  		return &fileStat{name: basename(file.name), filetype: ft}, nil
    35  	}
    36  
    37  	fs, err := newFileStatFromGetFileInformationByHandle(file.name, file.pfd.Sysfd)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	fs.filetype = ft
    42  	return fs, err
    43  }
    44  
    45  // stat implements both Stat and Lstat of a file.
    46  func stat(funcname, name string, createFileAttrs uint32) (FileInfo, error) {
    47  	if len(name) == 0 {
    48  		return nil, &PathError{Op: funcname, Path: name, Err: syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
    49  	}
    50  	if isWindowsNulName(name) {
    51  		return &devNullStat, nil
    52  	}
    53  	namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
    54  	if err != nil {
    55  		return nil, &PathError{Op: funcname, Path: name, Err: err}
    56  	}
    57  
    58  	// Try GetFileAttributesEx first, because it is faster than CreateFile.
    59  	// See https://golang.org/issues/19922#issuecomment-300031421 for details.
    60  	var fa syscall.Win32FileAttributeData
    61  	err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
    62  	if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
    63  		// Not a symlink.
    64  		fs := &fileStat{
    65  			FileAttributes: fa.FileAttributes,
    66  			CreationTime:   fa.CreationTime,
    67  			LastAccessTime: fa.LastAccessTime,
    68  			LastWriteTime:  fa.LastWriteTime,
    69  			FileSizeHigh:   fa.FileSizeHigh,
    70  			FileSizeLow:    fa.FileSizeLow,
    71  		}
    72  		if err := fs.saveInfoFromPath(name); err != nil {
    73  			return nil, err
    74  		}
    75  		return fs, nil
    76  	}
    77  	// GetFileAttributesEx fails with ERROR_SHARING_VIOLATION error for
    78  	// files, like c:\pagefile.sys. Use FindFirstFile for such files.
    79  	if err == windows.ERROR_SHARING_VIOLATION {
    80  		var fd syscall.Win32finddata
    81  		sh, err := syscall.FindFirstFile(namep, &fd)
    82  		if err != nil {
    83  			return nil, &PathError{Op: "FindFirstFile", Path: name, Err: err}
    84  		}
    85  		syscall.FindClose(sh)
    86  		fs := newFileStatFromWin32finddata(&fd)
    87  		if err := fs.saveInfoFromPath(name); err != nil {
    88  			return nil, err
    89  		}
    90  		return fs, nil
    91  	}
    92  
    93  	// Finally use CreateFile.
    94  	h, err := syscall.CreateFile(namep, 0, 0, nil,
    95  		syscall.OPEN_EXISTING, createFileAttrs, 0)
    96  	if err != nil {
    97  		return nil, &PathError{Op: "CreateFile", Path: name, Err: err}
    98  	}
    99  	defer syscall.CloseHandle(h)
   100  
   101  	return newFileStatFromGetFileInformationByHandle(name, h)
   102  }
   103  
   104  // statNolog implements Stat for Windows.
   105  func statNolog(name string) (FileInfo, error) {
   106  	return stat("Stat", name, syscall.FILE_FLAG_BACKUP_SEMANTICS)
   107  }
   108  
   109  // lstatNolog implements Lstat for Windows.
   110  func lstatNolog(name string) (FileInfo, error) {
   111  	attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
   112  	// Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
   113  	// See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
   114  	attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
   115  	return stat("Lstat", name, attrs)
   116  }
   117  

View as plain text