mirror of
https://github.com/golang/go
synced 2024-11-14 08:50:22 -07:00
48c4eeeed7
Also add more tests to test both nul and NUL on windows. Fixes #24482 Change-Id: I3dfe68ec8de7f90ca869c1096dde0054df3c5cf6 Reviewed-on: https://go-review.googlesource.com/102457 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
118 lines
2.9 KiB
Go
118 lines
2.9 KiB
Go
// 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 (
|
|
"syscall"
|
|
)
|
|
|
|
// isNulName returns true if name is NUL file name.
|
|
// For example, it returns true for both "NUL" and "nul".
|
|
func isNulName(name string) bool {
|
|
if len(name) != 3 {
|
|
return false
|
|
}
|
|
if name[0] != 'n' && name[0] != 'N' {
|
|
return false
|
|
}
|
|
if name[1] != 'u' && name[1] != 'U' {
|
|
return false
|
|
}
|
|
if name[2] != 'l' && name[2] != 'L' {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Stat returns the FileInfo structure describing file.
|
|
// If there is an error, it will be of type *PathError.
|
|
func (file *File) Stat() (FileInfo, error) {
|
|
if file == nil {
|
|
return nil, ErrInvalid
|
|
}
|
|
|
|
if file.isdir() {
|
|
// I don't know any better way to do that for directory
|
|
return Stat(file.dirinfo.path)
|
|
}
|
|
if isNulName(file.name) {
|
|
return &devNullStat, nil
|
|
}
|
|
|
|
ft, err := file.pfd.GetFileType()
|
|
if err != nil {
|
|
return nil, &PathError{"GetFileType", file.name, err}
|
|
}
|
|
switch ft {
|
|
case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
|
|
return &fileStat{name: basename(file.name), filetype: ft}, nil
|
|
}
|
|
|
|
fs, err := newFileStatFromGetFileInformationByHandle(file.name, file.pfd.Sysfd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
fs.filetype = ft
|
|
return fs, err
|
|
}
|
|
|
|
// statNolog implements Stat for Windows.
|
|
func statNolog(name string) (FileInfo, error) {
|
|
if len(name) == 0 {
|
|
return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
|
|
}
|
|
if isNulName(name) {
|
|
return &devNullStat, nil
|
|
}
|
|
namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
|
|
if err != nil {
|
|
return nil, &PathError{"Stat", name, err}
|
|
}
|
|
fs, err := newFileStatFromGetFileAttributesExOrFindFirstFile(name, namep)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !fs.isSymlink() {
|
|
err = fs.updatePathAndName(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return fs, nil
|
|
}
|
|
// Use Windows I/O manager to dereference the symbolic link, as per
|
|
// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
|
|
h, err := syscall.CreateFile(namep, 0, 0, nil,
|
|
syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
|
|
if err != nil {
|
|
return nil, &PathError{"CreateFile", name, err}
|
|
}
|
|
defer syscall.CloseHandle(h)
|
|
|
|
return newFileStatFromGetFileInformationByHandle(name, h)
|
|
}
|
|
|
|
// lstatNolog implements Lstat for Windows.
|
|
func lstatNolog(name string) (FileInfo, error) {
|
|
if len(name) == 0 {
|
|
return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
|
|
}
|
|
if isNulName(name) {
|
|
return &devNullStat, nil
|
|
}
|
|
namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
|
|
if err != nil {
|
|
return nil, &PathError{"Lstat", name, err}
|
|
}
|
|
fs, err := newFileStatFromGetFileAttributesExOrFindFirstFile(name, namep)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = fs.updatePathAndName(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return fs, nil
|
|
}
|