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.
Этот коммит содержится в:
		
							родитель
							
								
									5127b9d65b
								
							
						
					
					
						коммит
						ec9fd3fb38
					
				
					 17 изменённых файлов: 1118 добавлений и 25 удалений
				
			
		
							
								
								
									
										12
									
								
								src/os/export_windows_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										12
									
								
								src/os/export_windows_test.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					// Copyright 2016 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Export for testing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						FixLongPath     = fixLongPath
 | 
				
			||||||
 | 
						CanUseLongPaths = canUseLongPaths
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -171,11 +171,6 @@ func (f *File) Stat() (FileInfo, error) {
 | 
				
			||||||
	return nil, &PathError{"stat", f.name, ErrNotImplemented}
 | 
						return nil, &PathError{"stat", f.name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sync is a stub, not yet implemented
 | 
					 | 
				
			||||||
func (f *File) Sync() error {
 | 
					 | 
				
			||||||
	return ErrNotImplemented
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (f *File) SyscallConn() (syscall.RawConn, error) {
 | 
					func (f *File) SyscallConn() (syscall.RawConn, error) {
 | 
				
			||||||
	return nil, ErrNotImplemented
 | 
						return nil, ErrNotImplemented
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -190,16 +185,6 @@ func (f *File) Truncate(size int64) error {
 | 
				
			||||||
	return &PathError{"truncate", f.name, ErrNotImplemented}
 | 
						return &PathError{"truncate", f.name, ErrNotImplemented}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	PathSeparator     = '/' // OS-specific path separator
 | 
					 | 
				
			||||||
	PathListSeparator = ':' // OS-specific path list separator
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsPathSeparator reports whether c is a directory separator character.
 | 
					 | 
				
			||||||
func IsPathSeparator(c uint8) bool {
 | 
					 | 
				
			||||||
	return PathSeparator == c
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// PathError records an error and the operation and file path that caused it.
 | 
					// PathError records an error and the operation and file path that caused it.
 | 
				
			||||||
// TODO: PathError moved to io/fs in go 1.16 and left an alias in os/errors.go.
 | 
					// TODO: PathError moved to io/fs in go 1.16 and left an alias in os/errors.go.
 | 
				
			||||||
// Do the same once we drop support for go 1.15.
 | 
					// Do the same once we drop support for go 1.15.
 | 
				
			||||||
| 
						 | 
					@ -245,16 +230,6 @@ const (
 | 
				
			||||||
	O_TRUNC  int = syscall.O_TRUNC
 | 
						O_TRUNC  int = syscall.O_TRUNC
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stat is a stub, not yet implemented
 | 
					 | 
				
			||||||
func Stat(name string) (FileInfo, error) {
 | 
					 | 
				
			||||||
	return nil, &PathError{"stat", name, ErrNotImplemented}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Lstat is a stub, not yet implemented
 | 
					 | 
				
			||||||
func Lstat(name string) (FileInfo, error) {
 | 
					 | 
				
			||||||
	return nil, &PathError{"lstat", name, ErrNotImplemented}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func Getwd() (string, error) {
 | 
					func Getwd() (string, error) {
 | 
				
			||||||
	return syscall.Getwd()
 | 
						return syscall.Getwd()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,3 +50,19 @@ func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ignoringEINTR makes a function call and repeats it if it returns an
 | 
				
			||||||
 | 
					// EINTR error. This appears to be required even though we install all
 | 
				
			||||||
 | 
					// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
 | 
				
			||||||
 | 
					// Also #20400 and #36644 are issues in which a signal handler is
 | 
				
			||||||
 | 
					// installed without setting SA_RESTART. None of these are the common case,
 | 
				
			||||||
 | 
					// but there are enough of them that it seems that we can't avoid
 | 
				
			||||||
 | 
					// an EINTR loop.
 | 
				
			||||||
 | 
					func ignoringEINTR(fn func() error) error {
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							err := fn()
 | 
				
			||||||
 | 
							if err != syscall.EINTR {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,3 +56,21 @@ func tempDir() string {
 | 
				
			||||||
func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
 | 
					func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
 | 
				
			||||||
	return -1, ErrNotImplemented
 | 
						return -1, ErrNotImplemented
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// isWindowsNulName reports whether name is os.DevNull ('NUL') on Windows.
 | 
				
			||||||
 | 
					// True is returned if name is 'NUL' whatever the case.
 | 
				
			||||||
 | 
					func isWindowsNulName(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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/os/path_unix.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										35
									
								
								src/os/path_unix.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					// +build darwin linux,!baremetal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copyright 2011 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						PathSeparator     = '/' // OS-specific path separator
 | 
				
			||||||
 | 
						PathListSeparator = ':' // OS-specific path list separator
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsPathSeparator reports whether c is a directory separator character.
 | 
				
			||||||
 | 
					func IsPathSeparator(c uint8) bool {
 | 
				
			||||||
 | 
						return PathSeparator == c
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// basename removes trailing slashes and the leading directory name from path name.
 | 
				
			||||||
 | 
					func basename(name string) string {
 | 
				
			||||||
 | 
						i := len(name) - 1
 | 
				
			||||||
 | 
						// Remove trailing slashes
 | 
				
			||||||
 | 
						for ; i > 0 && name[i] == '/'; i-- {
 | 
				
			||||||
 | 
							name = name[:i]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Remove leading directory name
 | 
				
			||||||
 | 
						for i--; i >= 0; i-- {
 | 
				
			||||||
 | 
							if name[i] == '/' {
 | 
				
			||||||
 | 
								name = name[i+1:]
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										216
									
								
								src/os/path_windows.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										216
									
								
								src/os/path_windows.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,216 @@
 | 
				
			||||||
 | 
					// Copyright 2011 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						PathSeparator     = '\\' // OS-specific path separator
 | 
				
			||||||
 | 
						PathListSeparator = ';'  // OS-specific path list separator
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsPathSeparator reports whether c is a directory separator character.
 | 
				
			||||||
 | 
					func IsPathSeparator(c uint8) bool {
 | 
				
			||||||
 | 
						// NOTE: Windows accept / as path separator.
 | 
				
			||||||
 | 
						return c == '\\' || c == '/'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// basename removes trailing slashes and the leading
 | 
				
			||||||
 | 
					// directory name and drive letter from path name.
 | 
				
			||||||
 | 
					func basename(name string) string {
 | 
				
			||||||
 | 
						// Remove drive letter
 | 
				
			||||||
 | 
						if len(name) == 2 && name[1] == ':' {
 | 
				
			||||||
 | 
							name = "."
 | 
				
			||||||
 | 
						} else if len(name) > 2 && name[1] == ':' {
 | 
				
			||||||
 | 
							name = name[2:]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i := len(name) - 1
 | 
				
			||||||
 | 
						// Remove trailing slashes
 | 
				
			||||||
 | 
						for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
 | 
				
			||||||
 | 
							name = name[:i]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Remove leading directory name
 | 
				
			||||||
 | 
						for i--; i >= 0; i-- {
 | 
				
			||||||
 | 
							if name[i] == '/' || name[i] == '\\' {
 | 
				
			||||||
 | 
								name = name[i+1:]
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return name
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isAbs(path string) (b bool) {
 | 
				
			||||||
 | 
						v := volumeName(path)
 | 
				
			||||||
 | 
						if v == "" {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						path = path[len(v):]
 | 
				
			||||||
 | 
						if path == "" {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return IsPathSeparator(path[0])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func volumeName(path string) (v string) {
 | 
				
			||||||
 | 
						if len(path) < 2 {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// with drive letter
 | 
				
			||||||
 | 
						c := path[0]
 | 
				
			||||||
 | 
						if path[1] == ':' &&
 | 
				
			||||||
 | 
							('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
 | 
				
			||||||
 | 
								'A' <= c && c <= 'Z') {
 | 
				
			||||||
 | 
							return path[:2]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// is it UNC
 | 
				
			||||||
 | 
						if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
 | 
				
			||||||
 | 
							!IsPathSeparator(path[2]) && path[2] != '.' {
 | 
				
			||||||
 | 
							// first, leading `\\` and next shouldn't be `\`. its server name.
 | 
				
			||||||
 | 
							for n := 3; n < l-1; n++ {
 | 
				
			||||||
 | 
								// second, next '\' shouldn't be repeated.
 | 
				
			||||||
 | 
								if IsPathSeparator(path[n]) {
 | 
				
			||||||
 | 
									n++
 | 
				
			||||||
 | 
									// third, following something characters. its share name.
 | 
				
			||||||
 | 
									if !IsPathSeparator(path[n]) {
 | 
				
			||||||
 | 
										if path[n] == '.' {
 | 
				
			||||||
 | 
											break
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										for ; n < l; n++ {
 | 
				
			||||||
 | 
											if IsPathSeparator(path[n]) {
 | 
				
			||||||
 | 
												break
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return path[:n]
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fromSlash(path string) string {
 | 
				
			||||||
 | 
						// Replace each '/' with '\\' if present
 | 
				
			||||||
 | 
						var pathbuf []byte
 | 
				
			||||||
 | 
						var lastSlash int
 | 
				
			||||||
 | 
						for i, b := range path {
 | 
				
			||||||
 | 
							if b == '/' {
 | 
				
			||||||
 | 
								if pathbuf == nil {
 | 
				
			||||||
 | 
									pathbuf = make([]byte, len(path))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								copy(pathbuf[lastSlash:], path[lastSlash:i])
 | 
				
			||||||
 | 
								pathbuf[i] = '\\'
 | 
				
			||||||
 | 
								lastSlash = i + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if pathbuf == nil {
 | 
				
			||||||
 | 
							return path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						copy(pathbuf[lastSlash:], path[lastSlash:])
 | 
				
			||||||
 | 
						return string(pathbuf)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func dirname(path string) string {
 | 
				
			||||||
 | 
						vol := volumeName(path)
 | 
				
			||||||
 | 
						i := len(path) - 1
 | 
				
			||||||
 | 
						for i >= len(vol) && !IsPathSeparator(path[i]) {
 | 
				
			||||||
 | 
							i--
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dir := path[len(vol) : i+1]
 | 
				
			||||||
 | 
						last := len(dir) - 1
 | 
				
			||||||
 | 
						if last > 0 && IsPathSeparator(dir[last]) {
 | 
				
			||||||
 | 
							dir = dir[:last]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if dir == "" {
 | 
				
			||||||
 | 
							dir = "."
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return vol + dir
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS
 | 
				
			||||||
 | 
					// supports opting into proper long path handling without the need for fixups.
 | 
				
			||||||
 | 
					var canUseLongPaths bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// fixLongPath returns the extended-length (\\?\-prefixed) form of
 | 
				
			||||||
 | 
					// path when needed, in order to avoid the default 260 character file
 | 
				
			||||||
 | 
					// path limit imposed by Windows. If path is not easily converted to
 | 
				
			||||||
 | 
					// the extended-length form (for example, if path is a relative path
 | 
				
			||||||
 | 
					// or contains .. elements), or is short enough, fixLongPath returns
 | 
				
			||||||
 | 
					// path unmodified.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
 | 
				
			||||||
 | 
					func fixLongPath(path string) string {
 | 
				
			||||||
 | 
						if canUseLongPaths {
 | 
				
			||||||
 | 
							return path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Do nothing (and don't allocate) if the path is "short".
 | 
				
			||||||
 | 
						// Empirically (at least on the Windows Server 2013 builder),
 | 
				
			||||||
 | 
						// the kernel is arbitrarily okay with < 248 bytes. That
 | 
				
			||||||
 | 
						// matches what the docs above say:
 | 
				
			||||||
 | 
						// "When using an API to create a directory, the specified
 | 
				
			||||||
 | 
						// path cannot be so long that you cannot append an 8.3 file
 | 
				
			||||||
 | 
						// name (that is, the directory name cannot exceed MAX_PATH
 | 
				
			||||||
 | 
						// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// The MSDN docs appear to say that a normal path that is 248 bytes long
 | 
				
			||||||
 | 
						// will work; empirically the path must be less then 248 bytes long.
 | 
				
			||||||
 | 
						if len(path) < 248 {
 | 
				
			||||||
 | 
							// Don't fix. (This is how Go 1.7 and earlier worked,
 | 
				
			||||||
 | 
							// not automatically generating the \\?\ form)
 | 
				
			||||||
 | 
							return path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The extended form begins with \\?\, as in
 | 
				
			||||||
 | 
						// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
 | 
				
			||||||
 | 
						// The extended form disables evaluation of . and .. path
 | 
				
			||||||
 | 
						// elements and disables the interpretation of / as equivalent
 | 
				
			||||||
 | 
						// to \. The conversion here rewrites / to \ and elides
 | 
				
			||||||
 | 
						// . elements as well as trailing or duplicate separators. For
 | 
				
			||||||
 | 
						// simplicity it avoids the conversion entirely for relative
 | 
				
			||||||
 | 
						// paths or paths containing .. elements. For now,
 | 
				
			||||||
 | 
						// \\server\share paths are not converted to
 | 
				
			||||||
 | 
						// \\?\UNC\server\share paths because the rules for doing so
 | 
				
			||||||
 | 
						// are less well-specified.
 | 
				
			||||||
 | 
						if len(path) >= 2 && path[:2] == `\\` {
 | 
				
			||||||
 | 
							// Don't canonicalize UNC paths.
 | 
				
			||||||
 | 
							return path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !isAbs(path) {
 | 
				
			||||||
 | 
							// Relative path
 | 
				
			||||||
 | 
							return path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const prefix = `\\?`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
 | 
				
			||||||
 | 
						copy(pathbuf, prefix)
 | 
				
			||||||
 | 
						n := len(path)
 | 
				
			||||||
 | 
						r, w := 0, len(prefix)
 | 
				
			||||||
 | 
						for r < n {
 | 
				
			||||||
 | 
							switch {
 | 
				
			||||||
 | 
							case IsPathSeparator(path[r]):
 | 
				
			||||||
 | 
								// empty block
 | 
				
			||||||
 | 
								r++
 | 
				
			||||||
 | 
							case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
 | 
				
			||||||
 | 
								// /./
 | 
				
			||||||
 | 
								r++
 | 
				
			||||||
 | 
							case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
 | 
				
			||||||
 | 
								// /../ is currently unhandled
 | 
				
			||||||
 | 
								return path
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								pathbuf[w] = '\\'
 | 
				
			||||||
 | 
								w++
 | 
				
			||||||
 | 
								for ; r < n && !IsPathSeparator(path[r]); r++ {
 | 
				
			||||||
 | 
									pathbuf[w] = path[r]
 | 
				
			||||||
 | 
									w++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// A drive's root directory needs a trailing \
 | 
				
			||||||
 | 
						if w == len(`\\?\c:`) {
 | 
				
			||||||
 | 
							pathbuf[w] = '\\'
 | 
				
			||||||
 | 
							w++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return string(pathbuf[:w])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/os/stat.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										21
									
								
								src/os/stat.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					// +build !baremetal,!js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copyright 2017 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stat returns a FileInfo describing the named file.
 | 
				
			||||||
 | 
					// If there is an error, it will be of type *PathError.
 | 
				
			||||||
 | 
					func Stat(name string) (FileInfo, error) {
 | 
				
			||||||
 | 
						return statNolog(name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Lstat returns a FileInfo describing the named file.
 | 
				
			||||||
 | 
					// If the file is a symbolic link, the returned FileInfo
 | 
				
			||||||
 | 
					// describes the symbolic link. Lstat makes no attempt to follow the link.
 | 
				
			||||||
 | 
					// If there is an error, it will be of type *PathError.
 | 
				
			||||||
 | 
					func Lstat(name string) (FileInfo, error) {
 | 
				
			||||||
 | 
						return lstatNolog(name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/os/stat_darwin.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										51
									
								
								src/os/stat_darwin.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					// 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"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fillFileStatFromSys(fs *fileStat, name string) {
 | 
				
			||||||
 | 
						fs.name = basename(name)
 | 
				
			||||||
 | 
						fs.size = fs.sys.Size
 | 
				
			||||||
 | 
						fs.modTime = timespecToTime(fs.sys.Mtim)
 | 
				
			||||||
 | 
						fs.mode = FileMode(fs.sys.Mode & 0777)
 | 
				
			||||||
 | 
						switch fs.sys.Mode & syscall.S_IFMT {
 | 
				
			||||||
 | 
						case syscall.S_IFBLK, syscall.S_IFWHT:
 | 
				
			||||||
 | 
							fs.mode |= ModeDevice
 | 
				
			||||||
 | 
						case syscall.S_IFCHR:
 | 
				
			||||||
 | 
							fs.mode |= ModeDevice | ModeCharDevice
 | 
				
			||||||
 | 
						case syscall.S_IFDIR:
 | 
				
			||||||
 | 
							fs.mode |= ModeDir
 | 
				
			||||||
 | 
						case syscall.S_IFIFO:
 | 
				
			||||||
 | 
							fs.mode |= ModeNamedPipe
 | 
				
			||||||
 | 
						case syscall.S_IFLNK:
 | 
				
			||||||
 | 
							fs.mode |= ModeSymlink
 | 
				
			||||||
 | 
						case syscall.S_IFREG:
 | 
				
			||||||
 | 
							// nothing to do
 | 
				
			||||||
 | 
						case syscall.S_IFSOCK:
 | 
				
			||||||
 | 
							fs.mode |= ModeSocket
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.sys.Mode&syscall.S_ISGID != 0 {
 | 
				
			||||||
 | 
							fs.mode |= ModeSetgid
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.sys.Mode&syscall.S_ISUID != 0 {
 | 
				
			||||||
 | 
							fs.mode |= ModeSetuid
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.sys.Mode&syscall.S_ISVTX != 0 {
 | 
				
			||||||
 | 
							fs.mode |= ModeSticky
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func timespecToTime(ts syscall.Timespec) time.Time {
 | 
				
			||||||
 | 
						return time.Unix(int64(ts.Sec), int64(ts.Nsec))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// For testing.
 | 
				
			||||||
 | 
					func atime(fi FileInfo) time.Time {
 | 
				
			||||||
 | 
						return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/os/stat_linux.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										53
									
								
								src/os/stat_linux.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					// +build linux,!baremetal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fillFileStatFromSys(fs *fileStat, name string) {
 | 
				
			||||||
 | 
						fs.name = basename(name)
 | 
				
			||||||
 | 
						fs.size = fs.sys.Size
 | 
				
			||||||
 | 
						fs.modTime = timespecToTime(fs.sys.Mtim)
 | 
				
			||||||
 | 
						fs.mode = FileMode(fs.sys.Mode & 0777)
 | 
				
			||||||
 | 
						switch fs.sys.Mode & syscall.S_IFMT {
 | 
				
			||||||
 | 
						case syscall.S_IFBLK:
 | 
				
			||||||
 | 
							fs.mode |= ModeDevice
 | 
				
			||||||
 | 
						case syscall.S_IFCHR:
 | 
				
			||||||
 | 
							fs.mode |= ModeDevice | ModeCharDevice
 | 
				
			||||||
 | 
						case syscall.S_IFDIR:
 | 
				
			||||||
 | 
							fs.mode |= ModeDir
 | 
				
			||||||
 | 
						case syscall.S_IFIFO:
 | 
				
			||||||
 | 
							fs.mode |= ModeNamedPipe
 | 
				
			||||||
 | 
						case syscall.S_IFLNK:
 | 
				
			||||||
 | 
							fs.mode |= ModeSymlink
 | 
				
			||||||
 | 
						case syscall.S_IFREG:
 | 
				
			||||||
 | 
							// nothing to do
 | 
				
			||||||
 | 
						case syscall.S_IFSOCK:
 | 
				
			||||||
 | 
							fs.mode |= ModeSocket
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.sys.Mode&syscall.S_ISGID != 0 {
 | 
				
			||||||
 | 
							fs.mode |= ModeSetgid
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.sys.Mode&syscall.S_ISUID != 0 {
 | 
				
			||||||
 | 
							fs.mode |= ModeSetuid
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.sys.Mode&syscall.S_ISVTX != 0 {
 | 
				
			||||||
 | 
							fs.mode |= ModeSticky
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func timespecToTime(ts syscall.Timespec) time.Time {
 | 
				
			||||||
 | 
						return time.Unix(int64(ts.Sec), int64(ts.Nsec))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// For testing.
 | 
				
			||||||
 | 
					func atime(fi FileInfo) time.Time {
 | 
				
			||||||
 | 
						return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										96
									
								
								src/os/stat_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										96
									
								
								src/os/stat_test.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					// Copyright 2018 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_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io/fs"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// testStatAndLstat verifies that all os.Stat, os.Lstat os.File.Stat and os.Readdir work.
 | 
				
			||||||
 | 
					func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCheck func(*testing.T, string, fs.FileInfo)) {
 | 
				
			||||||
 | 
						// TODO: revert to upstream test once fstat and readdir are implemented
 | 
				
			||||||
 | 
						// test os.Stat
 | 
				
			||||||
 | 
						sfi, err := os.Stat(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						statCheck(t, path, sfi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// test os.Lstat
 | 
				
			||||||
 | 
						lsfi, err := os.Lstat(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lstatCheck(t, path, lsfi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if isLink {
 | 
				
			||||||
 | 
							if os.SameFile(sfi, lsfi) {
 | 
				
			||||||
 | 
								t.Errorf("stat and lstat of %q should not be the same", path)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if !os.SameFile(sfi, lsfi) {
 | 
				
			||||||
 | 
								t.Errorf("stat and lstat of %q should be the same", path)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// testIsDir verifies that fi refers to directory.
 | 
				
			||||||
 | 
					func testIsDir(t *testing.T, path string, fi fs.FileInfo) {
 | 
				
			||||||
 | 
						t.Helper()
 | 
				
			||||||
 | 
						if !fi.IsDir() {
 | 
				
			||||||
 | 
							t.Errorf("%q should be a directory", path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fi.Mode()&fs.ModeSymlink != 0 {
 | 
				
			||||||
 | 
							t.Errorf("%q should not be a symlink", path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// testIsFile verifies that fi refers to file.
 | 
				
			||||||
 | 
					func testIsFile(t *testing.T, path string, fi fs.FileInfo) {
 | 
				
			||||||
 | 
						t.Helper()
 | 
				
			||||||
 | 
						if fi.IsDir() {
 | 
				
			||||||
 | 
							t.Errorf("%q should not be a directory", path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fi.Mode()&fs.ModeSymlink != 0 {
 | 
				
			||||||
 | 
							t.Errorf("%q should not be a symlink", path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testDirStats(t *testing.T, path string) {
 | 
				
			||||||
 | 
						testStatAndLstat(t, path, false, testIsDir, testIsDir)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testFileStats(t *testing.T, path string) {
 | 
				
			||||||
 | 
						testStatAndLstat(t, path, false, testIsFile, testIsFile)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDirAndSymlinkStats(t *testing.T) {
 | 
				
			||||||
 | 
						// TODO: revert to upstream test once symlinks and t.TempDir are implemented
 | 
				
			||||||
 | 
						tmpdir := os.TempDir()
 | 
				
			||||||
 | 
						dir := filepath.Join(tmpdir, "dir")
 | 
				
			||||||
 | 
						os.Remove(dir)
 | 
				
			||||||
 | 
						if err := os.Mkdir(dir, 0777); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						testDirStats(t, dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestFileAndSymlinkStats(t *testing.T) {
 | 
				
			||||||
 | 
						// TODO: revert to upstream test once symlinks and t.TempDir are implemented
 | 
				
			||||||
 | 
						tmpdir := os.TempDir()
 | 
				
			||||||
 | 
						file := filepath.Join(tmpdir, "file")
 | 
				
			||||||
 | 
						if err := os.WriteFile(file, []byte("abcdefg"), 0644); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						testFileStats(t, file)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/os/stat_unix.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										42
									
								
								src/os/stat_unix.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					// +build darwin linux,!baremetal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copyright 2016 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"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sync is a stub, not yet implemented
 | 
				
			||||||
 | 
					func (f *File) Sync() error {
 | 
				
			||||||
 | 
						return ErrNotImplemented
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// statNolog stats a file with no test logging.
 | 
				
			||||||
 | 
					func statNolog(name string) (FileInfo, error) {
 | 
				
			||||||
 | 
						var fs fileStat
 | 
				
			||||||
 | 
						err := ignoringEINTR(func() error {
 | 
				
			||||||
 | 
							return syscall.Stat(name, &fs.sys)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, &PathError{Op: "stat", Path: name, Err: err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fillFileStatFromSys(&fs, name)
 | 
				
			||||||
 | 
						return &fs, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// lstatNolog lstats a file with no test logging.
 | 
				
			||||||
 | 
					func lstatNolog(name string) (FileInfo, error) {
 | 
				
			||||||
 | 
						var fs fileStat
 | 
				
			||||||
 | 
						err := ignoringEINTR(func() error {
 | 
				
			||||||
 | 
							return syscall.Lstat(name, &fs.sys)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, &PathError{Op: "lstat", Path: name, Err: err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fillFileStatFromSys(&fs, name)
 | 
				
			||||||
 | 
						return &fs, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								src/os/stat_windows.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										89
									
								
								src/os/stat_windows.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/os/types.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										25
									
								
								src/os/types.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					// +build !baremetal,!js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) Name() string { return fs.name }
 | 
				
			||||||
 | 
					func (fs *fileStat) IsDir() bool  { return fs.Mode().IsDir() }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SameFile reports whether fi1 and fi2 describe the same file.
 | 
				
			||||||
 | 
					// For example, on Unix this means that the device and inode fields
 | 
				
			||||||
 | 
					// of the two underlying structures are identical; on other systems
 | 
				
			||||||
 | 
					// the decision may be based on the path names.
 | 
				
			||||||
 | 
					// SameFile only applies to results returned by this package's Stat.
 | 
				
			||||||
 | 
					// It returns false in other cases.
 | 
				
			||||||
 | 
					func SameFile(fi1, fi2 FileInfo) bool {
 | 
				
			||||||
 | 
						fs1, ok1 := fi1.(*fileStat)
 | 
				
			||||||
 | 
						fs2, ok2 := fi2.(*fileStat)
 | 
				
			||||||
 | 
						if !ok1 || !ok2 {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sameFile(fs1, fs2)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/os/types_unix.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										30
									
								
								src/os/types_unix.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					// +build darwin linux,!baremetal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
 | 
				
			||||||
 | 
					type fileStat struct {
 | 
				
			||||||
 | 
						name    string
 | 
				
			||||||
 | 
						size    int64
 | 
				
			||||||
 | 
						mode    FileMode
 | 
				
			||||||
 | 
						modTime time.Time
 | 
				
			||||||
 | 
						sys     syscall.Stat_t
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) Size() int64        { return fs.size }
 | 
				
			||||||
 | 
					func (fs *fileStat) Mode() FileMode     { return fs.mode }
 | 
				
			||||||
 | 
					func (fs *fileStat) ModTime() time.Time { return fs.modTime }
 | 
				
			||||||
 | 
					func (fs *fileStat) Sys() interface{}   { return &fs.sys }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sameFile(fs1, fs2 *fileStat) bool {
 | 
				
			||||||
 | 
						return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										231
									
								
								src/os/types_windows.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										231
									
								
								src/os/types_windows.go
									
										
									
									
									
										Обычный файл
									
								
							| 
						 | 
					@ -0,0 +1,231 @@
 | 
				
			||||||
 | 
					// 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"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"syscall"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
						"unsafe"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
 | 
				
			||||||
 | 
					type fileStat struct {
 | 
				
			||||||
 | 
						name string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// from ByHandleFileInformation, Win32FileAttributeData and Win32finddata
 | 
				
			||||||
 | 
						FileAttributes uint32
 | 
				
			||||||
 | 
						CreationTime   syscall.Filetime
 | 
				
			||||||
 | 
						LastAccessTime syscall.Filetime
 | 
				
			||||||
 | 
						LastWriteTime  syscall.Filetime
 | 
				
			||||||
 | 
						FileSizeHigh   uint32
 | 
				
			||||||
 | 
						FileSizeLow    uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// from Win32finddata
 | 
				
			||||||
 | 
						Reserved0 uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// what syscall.GetFileType returns
 | 
				
			||||||
 | 
						filetype uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// used to implement SameFile
 | 
				
			||||||
 | 
						sync.Mutex
 | 
				
			||||||
 | 
						path             string
 | 
				
			||||||
 | 
						vol              uint32
 | 
				
			||||||
 | 
						idxhi            uint32
 | 
				
			||||||
 | 
						idxlo            uint32
 | 
				
			||||||
 | 
						appendNameToPath bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// newFileStatFromGetFileInformationByHandle calls GetFileInformationByHandle
 | 
				
			||||||
 | 
					// to gather all required information about the file handle h.
 | 
				
			||||||
 | 
					func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (fs *fileStat, err error) {
 | 
				
			||||||
 | 
						var d syscall.ByHandleFileInformation
 | 
				
			||||||
 | 
						err = syscall.GetFileInformationByHandle(h, &d)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, &PathError{Op: "GetFileInformationByHandle", Path: path, Err: err}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var ti windows.FILE_ATTRIBUTE_TAG_INFO
 | 
				
			||||||
 | 
						err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti)))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if errno, ok := err.(syscall.Errno); ok && errno == windows.ERROR_INVALID_PARAMETER {
 | 
				
			||||||
 | 
								// It appears calling GetFileInformationByHandleEx with
 | 
				
			||||||
 | 
								// FILE_ATTRIBUTE_TAG_INFO fails on FAT file system with
 | 
				
			||||||
 | 
								// ERROR_INVALID_PARAMETER. Clear ti.ReparseTag in that
 | 
				
			||||||
 | 
								// instance to indicate no symlinks are possible.
 | 
				
			||||||
 | 
								ti.ReparseTag = 0
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return nil, &PathError{Op: "GetFileInformationByHandleEx", Path: path, Err: err}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &fileStat{
 | 
				
			||||||
 | 
							name:           basename(path),
 | 
				
			||||||
 | 
							FileAttributes: d.FileAttributes,
 | 
				
			||||||
 | 
							CreationTime:   d.CreationTime,
 | 
				
			||||||
 | 
							LastAccessTime: d.LastAccessTime,
 | 
				
			||||||
 | 
							LastWriteTime:  d.LastWriteTime,
 | 
				
			||||||
 | 
							FileSizeHigh:   d.FileSizeHigh,
 | 
				
			||||||
 | 
							FileSizeLow:    d.FileSizeLow,
 | 
				
			||||||
 | 
							vol:            d.VolumeSerialNumber,
 | 
				
			||||||
 | 
							idxhi:          d.FileIndexHigh,
 | 
				
			||||||
 | 
							idxlo:          d.FileIndexLow,
 | 
				
			||||||
 | 
							Reserved0:      ti.ReparseTag,
 | 
				
			||||||
 | 
							// fileStat.path is used by os.SameFile to decide if it needs
 | 
				
			||||||
 | 
							// to fetch vol, idxhi and idxlo. But these are already set,
 | 
				
			||||||
 | 
							// so set fileStat.path to "" to prevent os.SameFile doing it again.
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// newFileStatFromWin32finddata copies all required information
 | 
				
			||||||
 | 
					// from syscall.Win32finddata d into the newly created fileStat.
 | 
				
			||||||
 | 
					func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat {
 | 
				
			||||||
 | 
						return &fileStat{
 | 
				
			||||||
 | 
							FileAttributes: d.FileAttributes,
 | 
				
			||||||
 | 
							CreationTime:   d.CreationTime,
 | 
				
			||||||
 | 
							LastAccessTime: d.LastAccessTime,
 | 
				
			||||||
 | 
							LastWriteTime:  d.LastWriteTime,
 | 
				
			||||||
 | 
							FileSizeHigh:   d.FileSizeHigh,
 | 
				
			||||||
 | 
							FileSizeLow:    d.FileSizeLow,
 | 
				
			||||||
 | 
							Reserved0:      d.Reserved0,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) isSymlink() bool {
 | 
				
			||||||
 | 
						// Use instructions described at
 | 
				
			||||||
 | 
						// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
 | 
				
			||||||
 | 
						// to recognize whether it's a symlink.
 | 
				
			||||||
 | 
						if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return fs.Reserved0 == syscall.IO_REPARSE_TAG_SYMLINK ||
 | 
				
			||||||
 | 
							fs.Reserved0 == windows.IO_REPARSE_TAG_MOUNT_POINT
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) Size() int64 {
 | 
				
			||||||
 | 
						return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) Mode() (m FileMode) {
 | 
				
			||||||
 | 
						if fs == &devNullStat {
 | 
				
			||||||
 | 
							return ModeDevice | ModeCharDevice | 0666
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
 | 
				
			||||||
 | 
							m |= 0444
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							m |= 0666
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.isSymlink() {
 | 
				
			||||||
 | 
							return m | ModeSymlink
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
 | 
				
			||||||
 | 
							m |= ModeDir | 0111
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch fs.filetype {
 | 
				
			||||||
 | 
						case syscall.FILE_TYPE_PIPE:
 | 
				
			||||||
 | 
							m |= ModeNamedPipe
 | 
				
			||||||
 | 
						case syscall.FILE_TYPE_CHAR:
 | 
				
			||||||
 | 
							m |= ModeDevice | ModeCharDevice
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return m
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) ModTime() time.Time {
 | 
				
			||||||
 | 
						return time.Unix(0, fs.LastWriteTime.Nanoseconds())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sys returns syscall.Win32FileAttributeData for file fs.
 | 
				
			||||||
 | 
					func (fs *fileStat) Sys() interface{} {
 | 
				
			||||||
 | 
						return &syscall.Win32FileAttributeData{
 | 
				
			||||||
 | 
							FileAttributes: fs.FileAttributes,
 | 
				
			||||||
 | 
							CreationTime:   fs.CreationTime,
 | 
				
			||||||
 | 
							LastAccessTime: fs.LastAccessTime,
 | 
				
			||||||
 | 
							LastWriteTime:  fs.LastWriteTime,
 | 
				
			||||||
 | 
							FileSizeHigh:   fs.FileSizeHigh,
 | 
				
			||||||
 | 
							FileSizeLow:    fs.FileSizeLow,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (fs *fileStat) loadFileId() error {
 | 
				
			||||||
 | 
						fs.Lock()
 | 
				
			||||||
 | 
						defer fs.Unlock()
 | 
				
			||||||
 | 
						if fs.path == "" {
 | 
				
			||||||
 | 
							// already done
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var path string
 | 
				
			||||||
 | 
						if fs.appendNameToPath {
 | 
				
			||||||
 | 
							path = fs.path + `\` + fs.name
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							path = fs.path
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pathp, err := syscall.UTF16PtrFromString(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
 | 
				
			||||||
 | 
						if fs.isSymlink() {
 | 
				
			||||||
 | 
							// 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
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer syscall.CloseHandle(h)
 | 
				
			||||||
 | 
						var i syscall.ByHandleFileInformation
 | 
				
			||||||
 | 
						err = syscall.GetFileInformationByHandle(h, &i)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fs.path = ""
 | 
				
			||||||
 | 
						fs.vol = i.VolumeSerialNumber
 | 
				
			||||||
 | 
						fs.idxhi = i.FileIndexHigh
 | 
				
			||||||
 | 
						fs.idxlo = i.FileIndexLow
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// saveInfoFromPath saves full path of the file to be used by os.SameFile later,
 | 
				
			||||||
 | 
					// and set name from path.
 | 
				
			||||||
 | 
					func (fs *fileStat) saveInfoFromPath(path string) error {
 | 
				
			||||||
 | 
						fs.path = path
 | 
				
			||||||
 | 
						if !isAbs(fs.path) {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							fs.path, err = syscall.FullPath(fs.path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return &PathError{Op: "FullPath", Path: path, Err: err}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fs.name = basename(path)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// devNullStat is fileStat structure describing DevNull file ("NUL").
 | 
				
			||||||
 | 
					var devNullStat = fileStat{
 | 
				
			||||||
 | 
						name: DevNull,
 | 
				
			||||||
 | 
						// hopefully this will work for SameFile
 | 
				
			||||||
 | 
						vol:   0,
 | 
				
			||||||
 | 
						idxhi: 0,
 | 
				
			||||||
 | 
						idxlo: 0,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sameFile(fs1, fs2 *fileStat) bool {
 | 
				
			||||||
 | 
						e := fs1.loadFileId()
 | 
				
			||||||
 | 
						if e != nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e = fs2.loadFileId()
 | 
				
			||||||
 | 
						if e != nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// For testing.
 | 
				
			||||||
 | 
					func atime(fi FileInfo) time.Time {
 | 
				
			||||||
 | 
						return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package syscall
 | 
					package syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"unsafe"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This file defines errno and constants to match the darwin libsystem ABI.
 | 
					// This file defines errno and constants to match the darwin libsystem ABI.
 | 
				
			||||||
// Values have been copied from src/syscall/zerrors_darwin_amd64.go.
 | 
					// Values have been copied from src/syscall/zerrors_darwin_amd64.go.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,3 +101,93 @@ const (
 | 
				
			||||||
	MAP_ANON      = 0x1000 // allocated from memory, swap space
 | 
						MAP_ANON      = 0x1000 // allocated from memory, swap space
 | 
				
			||||||
	MAP_ANONYMOUS = MAP_ANON
 | 
						MAP_ANONYMOUS = MAP_ANON
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Timespec struct {
 | 
				
			||||||
 | 
						Sec  int64
 | 
				
			||||||
 | 
						Nsec int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Go chose Linux's field names for Stat_t, see https://github.com/golang/go/issues/31735
 | 
				
			||||||
 | 
					type Stat_t struct {
 | 
				
			||||||
 | 
						Dev       int32
 | 
				
			||||||
 | 
						Mode      uint16
 | 
				
			||||||
 | 
						Nlink     uint16
 | 
				
			||||||
 | 
						Ino       uint64
 | 
				
			||||||
 | 
						Uid       uint32
 | 
				
			||||||
 | 
						Gid       uint32
 | 
				
			||||||
 | 
						Rdev      int32
 | 
				
			||||||
 | 
						Pad_cgo_0 [4]byte
 | 
				
			||||||
 | 
						Atim      Timespec
 | 
				
			||||||
 | 
						Mtim      Timespec
 | 
				
			||||||
 | 
						Ctim      Timespec
 | 
				
			||||||
 | 
						Btim      Timespec
 | 
				
			||||||
 | 
						Size      int64
 | 
				
			||||||
 | 
						Blocks    int64
 | 
				
			||||||
 | 
						Blksize   int32
 | 
				
			||||||
 | 
						Flags     uint32
 | 
				
			||||||
 | 
						Gen       uint32
 | 
				
			||||||
 | 
						Lspare    int32
 | 
				
			||||||
 | 
						Qspare    [2]int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Source: https://github.com/apple/darwin-xnu/blob/main/bsd/sys/_types/_s_ifmt.h
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						S_IEXEC  = 0x40
 | 
				
			||||||
 | 
						S_IFBLK  = 0x6000
 | 
				
			||||||
 | 
						S_IFCHR  = 0x2000
 | 
				
			||||||
 | 
						S_IFDIR  = 0x4000
 | 
				
			||||||
 | 
						S_IFIFO  = 0x1000
 | 
				
			||||||
 | 
						S_IFLNK  = 0xa000
 | 
				
			||||||
 | 
						S_IFMT   = 0xf000
 | 
				
			||||||
 | 
						S_IFREG  = 0x8000
 | 
				
			||||||
 | 
						S_IFSOCK = 0xc000
 | 
				
			||||||
 | 
						S_IFWHT  = 0xe000
 | 
				
			||||||
 | 
						S_IREAD  = 0x100
 | 
				
			||||||
 | 
						S_IRGRP  = 0x20
 | 
				
			||||||
 | 
						S_IROTH  = 0x4
 | 
				
			||||||
 | 
						S_IRUSR  = 0x100
 | 
				
			||||||
 | 
						S_IRWXG  = 0x38
 | 
				
			||||||
 | 
						S_IRWXO  = 0x7
 | 
				
			||||||
 | 
						S_IRWXU  = 0x1c0
 | 
				
			||||||
 | 
						S_ISGID  = 0x400
 | 
				
			||||||
 | 
						S_ISTXT  = 0x200
 | 
				
			||||||
 | 
						S_ISUID  = 0x800
 | 
				
			||||||
 | 
						S_ISVTX  = 0x200
 | 
				
			||||||
 | 
						S_IWGRP  = 0x10
 | 
				
			||||||
 | 
						S_IWOTH  = 0x2
 | 
				
			||||||
 | 
						S_IWRITE = 0x80
 | 
				
			||||||
 | 
						S_IWUSR  = 0x80
 | 
				
			||||||
 | 
						S_IXGRP  = 0x8
 | 
				
			||||||
 | 
						S_IXOTH  = 0x1
 | 
				
			||||||
 | 
						S_IXUSR  = 0x40
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Stat(path string, p *Stat_t) (err error) {
 | 
				
			||||||
 | 
						data := cstring(path)
 | 
				
			||||||
 | 
						n := libc_stat(&data[0], unsafe.Pointer(p))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n < 0 {
 | 
				
			||||||
 | 
							err = getErrno()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Lstat(path string, p *Stat_t) (err error) {
 | 
				
			||||||
 | 
						data := cstring(path)
 | 
				
			||||||
 | 
						n := libc_lstat(&data[0], unsafe.Pointer(p))
 | 
				
			||||||
 | 
						if n < 0 {
 | 
				
			||||||
 | 
							err = getErrno()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The odd $INODE64 suffix is an Apple compatibility feature, see https://assert.cc/posts/darwin_use_64_bit_inode_vs_ctypes/
 | 
				
			||||||
 | 
					// Without it, you get the old, smaller struct stat from mac os 10.2 or so.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// int stat(const char *path, struct stat * buf);
 | 
				
			||||||
 | 
					//export stat$INODE64
 | 
				
			||||||
 | 
					func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// int lstat(const char *path, struct stat * buf);
 | 
				
			||||||
 | 
					//export lstat$INODE64
 | 
				
			||||||
 | 
					func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package syscall
 | 
					package syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"unsafe"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt
 | 
					// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Signal int
 | 
					type Signal int
 | 
				
			||||||
| 
						 | 
					@ -139,3 +143,88 @@ const (
 | 
				
			||||||
	EXDEV           Errno = 75 /* Cross-device link */
 | 
						EXDEV           Errno = 75 /* Cross-device link */
 | 
				
			||||||
	ENOTCAPABLE     Errno = 76 /* Extension: Capabilities insufficient. */
 | 
						ENOTCAPABLE     Errno = 76 /* Extension: Capabilities insufficient. */
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__struct_timespec.h
 | 
				
			||||||
 | 
					type Timespec struct {
 | 
				
			||||||
 | 
						Sec  int32
 | 
				
			||||||
 | 
						Nsec int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__struct_stat.h
 | 
				
			||||||
 | 
					// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__typedef_ino_t.h
 | 
				
			||||||
 | 
					// etc.
 | 
				
			||||||
 | 
					// Go chose Linux's field names for Stat_t, see https://github.com/golang/go/issues/31735
 | 
				
			||||||
 | 
					type Stat_t struct {
 | 
				
			||||||
 | 
						Dev       uint64
 | 
				
			||||||
 | 
						Ino       uint64
 | 
				
			||||||
 | 
						Nlink     uint64
 | 
				
			||||||
 | 
						Mode      uint32
 | 
				
			||||||
 | 
						Uid       uint32
 | 
				
			||||||
 | 
						Gid       uint32
 | 
				
			||||||
 | 
						Pad_cgo_0 [4]byte
 | 
				
			||||||
 | 
						Rdev      uint64
 | 
				
			||||||
 | 
						Size      int64
 | 
				
			||||||
 | 
						Blksize   int32
 | 
				
			||||||
 | 
						Blocks    int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Atim   Timespec
 | 
				
			||||||
 | 
						Mtim   Timespec
 | 
				
			||||||
 | 
						Ctim   Timespec
 | 
				
			||||||
 | 
						Qspare [3]int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://github.com/WebAssembly/wasi-libc/blob/main/libc-top-half/musl/include/sys/stat.h
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						S_IFBLK  = 0x6000
 | 
				
			||||||
 | 
						S_IFCHR  = 0x2000
 | 
				
			||||||
 | 
						S_IFDIR  = 0x4000
 | 
				
			||||||
 | 
						S_IFIFO  = 0x1000
 | 
				
			||||||
 | 
						S_IFLNK  = 0xa000
 | 
				
			||||||
 | 
						S_IFMT   = 0xf000
 | 
				
			||||||
 | 
						S_IFREG  = 0x8000
 | 
				
			||||||
 | 
						S_IFSOCK = 0xc000
 | 
				
			||||||
 | 
						S_IREAD  = 0x100
 | 
				
			||||||
 | 
						S_IRGRP  = 0x20
 | 
				
			||||||
 | 
						S_IROTH  = 0x4
 | 
				
			||||||
 | 
						S_IRUSR  = 0x100
 | 
				
			||||||
 | 
						S_IRWXG  = 0x38
 | 
				
			||||||
 | 
						S_IRWXO  = 0x7
 | 
				
			||||||
 | 
						S_IRWXU  = 0x1c0
 | 
				
			||||||
 | 
						S_ISGID  = 0x400
 | 
				
			||||||
 | 
						S_ISUID  = 0x800
 | 
				
			||||||
 | 
						S_ISVTX  = 0x200
 | 
				
			||||||
 | 
						S_IWGRP  = 0x10
 | 
				
			||||||
 | 
						S_IWOTH  = 0x2
 | 
				
			||||||
 | 
						S_IWRITE = 0x80
 | 
				
			||||||
 | 
						S_IWUSR  = 0x80
 | 
				
			||||||
 | 
						S_IXGRP  = 0x8
 | 
				
			||||||
 | 
						S_IXOTH  = 0x1
 | 
				
			||||||
 | 
						S_IXUSR  = 0x40
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Stat(path string, p *Stat_t) (err error) {
 | 
				
			||||||
 | 
						data := cstring(path)
 | 
				
			||||||
 | 
						n := libc_stat(&data[0], unsafe.Pointer(p))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n < 0 {
 | 
				
			||||||
 | 
							err = getErrno()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Lstat(path string, p *Stat_t) (err error) {
 | 
				
			||||||
 | 
						data := cstring(path)
 | 
				
			||||||
 | 
						n := libc_lstat(&data[0], unsafe.Pointer(p))
 | 
				
			||||||
 | 
						if n < 0 {
 | 
				
			||||||
 | 
							err = getErrno()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// int stat(const char *path, struct stat * buf);
 | 
				
			||||||
 | 
					//export stat
 | 
				
			||||||
 | 
					func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// int lstat(const char *path, struct stat * buf);
 | 
				
			||||||
 | 
					//export lstat
 | 
				
			||||||
 | 
					func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче