mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-18 11:33:59 +00:00
os, syscall: implement Stat and Lstat
File.Stat is left as a stub for now. Tests are a bit stubbed down because os.ReadDir, os.Symlink, and t.TempDir are not yet (fully) implemented. TODO: reimport tests from upstream as those materialize.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"internal/syscall/windows"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Sync is a stub, not yet implemented
|
||||
func (f *File) Sync() error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// stat implements both Stat and Lstat of a file.
|
||||
func stat(funcname, name string, createFileAttrs uint32) (FileInfo, error) {
|
||||
if len(name) == 0 {
|
||||
return nil, &PathError{Op: funcname, Path: name, Err: syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
|
||||
}
|
||||
if isWindowsNulName(name) {
|
||||
return &devNullStat, nil
|
||||
}
|
||||
namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: funcname, Path: name, Err: err}
|
||||
}
|
||||
|
||||
// Try GetFileAttributesEx first, because it is faster than CreateFile.
|
||||
// See https://golang.org/issues/19922#issuecomment-300031421 for details.
|
||||
var fa syscall.Win32FileAttributeData
|
||||
err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
|
||||
if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
||||
// Not a symlink.
|
||||
fs := &fileStat{
|
||||
FileAttributes: fa.FileAttributes,
|
||||
CreationTime: fa.CreationTime,
|
||||
LastAccessTime: fa.LastAccessTime,
|
||||
LastWriteTime: fa.LastWriteTime,
|
||||
FileSizeHigh: fa.FileSizeHigh,
|
||||
FileSizeLow: fa.FileSizeLow,
|
||||
}
|
||||
if err := fs.saveInfoFromPath(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs, nil
|
||||
}
|
||||
// GetFileAttributesEx fails with ERROR_SHARING_VIOLATION error for
|
||||
// files, like c:\pagefile.sys. Use FindFirstFile for such files.
|
||||
if err == windows.ERROR_SHARING_VIOLATION {
|
||||
var fd syscall.Win32finddata
|
||||
sh, err := syscall.FindFirstFile(namep, &fd)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "FindFirstFile", Path: name, Err: err}
|
||||
}
|
||||
syscall.FindClose(sh)
|
||||
fs := newFileStatFromWin32finddata(&fd)
|
||||
if err := fs.saveInfoFromPath(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
// Finally use CreateFile.
|
||||
h, err := syscall.CreateFile(namep, 0, 0, nil,
|
||||
syscall.OPEN_EXISTING, createFileAttrs, 0)
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "CreateFile", Path: name, Err: err}
|
||||
}
|
||||
defer syscall.CloseHandle(h)
|
||||
|
||||
return newFileStatFromGetFileInformationByHandle(name, h)
|
||||
}
|
||||
|
||||
// statNolog implements Stat for Windows.
|
||||
func statNolog(name string) (FileInfo, error) {
|
||||
return stat("Stat", name, syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
}
|
||||
|
||||
// lstatNolog implements Lstat for Windows.
|
||||
func lstatNolog(name string) (FileInfo, error) {
|
||||
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
// Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
|
||||
// See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
|
||||
attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
|
||||
return stat("Lstat", name, attrs)
|
||||
}
|
||||
Reference in New Issue
Block a user