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