github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/os/stat_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  	"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  	if file == nil || file.pfd.Sysfd < 0 {
    20  		return nil, syscall.EINVAL
    21  	}
    22  	if file.isdir() {
    23  		// I don't know any better way to do that for directory
    24  		return Stat(file.dirinfo.path)
    25  	}
    26  	if file.name == DevNull {
    27  		return &devNullStat, nil
    28  	}
    29  
    30  	ft, err := file.pfd.GetFileType()
    31  	if err != nil {
    32  		return nil, &PathError{"GetFileType", file.name, err}
    33  	}
    34  	switch ft {
    35  	case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
    36  		return &fileStat{name: basename(file.name), filetype: ft}, nil
    37  	}
    38  
    39  	var d syscall.ByHandleFileInformation
    40  	err = file.pfd.GetFileInformationByHandle(&d)
    41  	if err != nil {
    42  		return nil, &PathError{"GetFileInformationByHandle", file.name, err}
    43  	}
    44  	return &fileStat{
    45  		name: basename(file.name),
    46  		sys: syscall.Win32FileAttributeData{
    47  			FileAttributes: d.FileAttributes,
    48  			CreationTime:   d.CreationTime,
    49  			LastAccessTime: d.LastAccessTime,
    50  			LastWriteTime:  d.LastWriteTime,
    51  			FileSizeHigh:   d.FileSizeHigh,
    52  			FileSizeLow:    d.FileSizeLow,
    53  		},
    54  		filetype: ft,
    55  		vol:      d.VolumeSerialNumber,
    56  		idxhi:    d.FileIndexHigh,
    57  		idxlo:    d.FileIndexLow,
    58  	}, nil
    59  }
    60  
    61  // Stat returns a FileInfo structure describing the named file.
    62  // If there is an error, it will be of type *PathError.
    63  func Stat(name string) (FileInfo, error) {
    64  	var fi FileInfo
    65  	var err error
    66  	for i := 0; i < 255; i++ {
    67  		fi, err = Lstat(name)
    68  		if err != nil {
    69  			return fi, err
    70  		}
    71  		if fi.Mode()&ModeSymlink == 0 {
    72  			return fi, nil
    73  		}
    74  		name, err = Readlink(name)
    75  		if err != nil {
    76  			return fi, err
    77  		}
    78  	}
    79  	return nil, &PathError{"Stat", name, syscall.ELOOP}
    80  }
    81  
    82  // Lstat returns the FileInfo structure describing the named file.
    83  // If the file is a symbolic link, the returned FileInfo
    84  // describes the symbolic link. Lstat makes no attempt to follow the link.
    85  // If there is an error, it will be of type *PathError.
    86  func Lstat(name string) (FileInfo, error) {
    87  	if len(name) == 0 {
    88  		return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
    89  	}
    90  	if name == DevNull {
    91  		return &devNullStat, nil
    92  	}
    93  	fs := &fileStat{name: basename(name)}
    94  	namep, e := syscall.UTF16PtrFromString(fixLongPath(name))
    95  	if e != nil {
    96  		return nil, &PathError{"Lstat", name, e}
    97  	}
    98  	e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys)))
    99  	if e != nil {
   100  		if e != windows.ERROR_SHARING_VIOLATION {
   101  			return nil, &PathError{"GetFileAttributesEx", name, e}
   102  		}
   103  		// try FindFirstFile now that GetFileAttributesEx failed
   104  		var fd syscall.Win32finddata
   105  		h, e2 := syscall.FindFirstFile(namep, &fd)
   106  		if e2 != nil {
   107  			return nil, &PathError{"FindFirstFile", name, e}
   108  		}
   109  		syscall.FindClose(h)
   110  
   111  		fs.sys.FileAttributes = fd.FileAttributes
   112  		fs.sys.CreationTime = fd.CreationTime
   113  		fs.sys.LastAccessTime = fd.LastAccessTime
   114  		fs.sys.LastWriteTime = fd.LastWriteTime
   115  		fs.sys.FileSizeHigh = fd.FileSizeHigh
   116  		fs.sys.FileSizeLow = fd.FileSizeLow
   117  	}
   118  	fs.path = name
   119  	if !isAbs(fs.path) {
   120  		fs.path, e = syscall.FullPath(fs.path)
   121  		if e != nil {
   122  			return nil, e
   123  		}
   124  	}
   125  	return fs, nil
   126  }