Commit 664c4a1f authored by Hiroshi Ioka's avatar Hiroshi Ioka Committed by Brad Fitzpatrick

os: consolidate files

Code movement only.

If someone finds function 'foo' in "foo_linux.go",
they will expect that the Window version of 'foo' exists in "foo_windows.go".

Current code doesn't follow this manner.

For example, 'sameFile' exists in "file_unix.go",
"stat_plan9.go" and "types_windows.go".

The CL address that problem by following rules:

* readdir family => dir.go, dir_$GOOS.go
* stat family => stat.go, stat_$GOOS.go
* path-functions => path_$GOOS.go
* sameFile => types.go, types_$GOOS.go
* process-functions => exec.go, exec_$GOOS.go
* hostname => sys.go, sys_$GOOS.go

Change-Id: Ic3c64663ce0b2a364d7a414351cd3c772e70187b
Reviewed-on: https://go-review.googlesource.com/27035
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent c307e162
// Copyright 2012 The Go Authors. All rights reserved.
// 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 "time"
// FindProcess looks for a running process by its pid.
//
// The Process it returns can be used to obtain information
// about the underlying operating system process.
//
// On Unix systems, FindProcess always succeeds and returns a Process
// for the given pid, regardless of whether the process exists.
func FindProcess(pid int) (*Process, error) {
return findProcess(pid)
}
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
//
// If there is an error, it will be of type *PathError.
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
return startProcess(name, argv, attr)
}
// Release releases any resources associated with the Process p,
// rendering it unusable in the future.
// Release only needs to be called if Wait is not.
func (p *Process) Release() error {
return p.release()
}
// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
return p.kill()
}
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
// Signal sends a signal to the Process.
// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
return p.signal(sig)
}
// UserTime returns the user CPU time of the exited process and its children.
func (p *ProcessState) UserTime() time.Duration {
return p.userTime()
}
// SystemTime returns the system CPU time of the exited process and its children.
func (p *ProcessState) SystemTime() time.Duration {
return p.systemTime()
}
// Exited reports whether the program has exited.
func (p *ProcessState) Exited() bool {
return p.exited()
}
// Success reports whether the program exited successfully,
// such as with exit status 0 on Unix.
func (p *ProcessState) Success() bool {
return p.success()
}
// Sys returns system-dependent exit information about
// the process. Convert it to the appropriate underlying
// type, such as syscall.WaitStatus on Unix, to access its contents.
func (p *ProcessState) Sys() interface{} {
return p.sys()
}
// SysUsage returns system-dependent resource usage information about
// the exited process. Convert it to the appropriate underlying
// type, such as *syscall.Rusage on Unix, to access its contents.
// (On Unix, *syscall.Rusage matches struct rusage as defined in the
// getrusage(2) manual page.)
func (p *ProcessState) SysUsage() interface{} {
return p.sysUsage()
}
// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err error) {
return hostname()
}
// Readdir reads the contents of the directory associated with file and
// returns a slice of up to n FileInfo values, as would be returned
// by Lstat, in directory order. Subsequent calls on the same file will yield
......
......@@ -15,6 +15,28 @@ const (
blockSize = 4096
)
func (f *File) readdir(n int) (fi []FileInfo, err error) {
dirname := f.name
if dirname == "" {
dirname = "."
}
names, err := f.Readdirnames(n)
fi = make([]FileInfo, 0, len(names))
for _, filename := range names {
fip, lerr := lstat(dirname + "/" + filename)
if IsNotExist(lerr) {
// File disappeared between readdir + stat.
// Just treat it as if it didn't exist.
continue
}
if lerr != nil {
return fi, lerr
}
fi = append(fi, fip)
}
return fi, err
}
func (f *File) readdirnames(n int) (names []string, err error) {
// If this file has no dirinfo, create one.
if f.dirinfo == nil {
......
......@@ -4,6 +4,70 @@
package os
import (
"io"
"syscall"
)
func (file *File) readdir(n int) (fi []FileInfo, err error) {
if file == nil {
return nil, syscall.EINVAL
}
if !file.isdir() {
return nil, &PathError{"Readdir", file.name, syscall.ENOTDIR}
}
if !file.dirinfo.isempty && file.fd == syscall.InvalidHandle {
return nil, syscall.EINVAL
}
wantAll := n <= 0
size := n
if wantAll {
n = -1
size = 100
}
fi = make([]FileInfo, 0, size) // Empty with room to grow.
d := &file.dirinfo.data
for n != 0 && !file.dirinfo.isempty {
if file.dirinfo.needdata {
e := syscall.FindNextFile(file.fd, d)
if e != nil {
if e == syscall.ERROR_NO_MORE_FILES {
break
} else {
err = &PathError{"FindNextFile", file.name, e}
if !wantAll {
fi = nil
}
return
}
}
}
file.dirinfo.needdata = true
name := syscall.UTF16ToString(d.FileName[0:])
if name == "." || name == ".." { // Useless names
continue
}
f := &fileStat{
name: name,
sys: syscall.Win32FileAttributeData{
FileAttributes: d.FileAttributes,
CreationTime: d.CreationTime,
LastAccessTime: d.LastAccessTime,
LastWriteTime: d.LastWriteTime,
FileSizeHigh: d.FileSizeHigh,
FileSizeLow: d.FileSizeLow,
},
path: file.dirinfo.path + `\` + name,
}
n--
fi = append(fi, f)
}
if !wantAll && len(fi) == 0 {
return fi, io.EOF
}
return fi, nil
}
func (file *File) readdirnames(n int) (names []string, err error) {
fis, err := file.Readdir(n)
names = make([]string, len(fis))
......
......@@ -9,6 +9,7 @@ import (
"sync"
"sync/atomic"
"syscall"
"time"
)
// Process stores the information about a process created by StartProcess.
......@@ -70,3 +71,89 @@ func Getpid() int { return syscall.Getpid() }
// Getppid returns the process id of the caller's parent.
func Getppid() int { return syscall.Getppid() }
// FindProcess looks for a running process by its pid.
//
// The Process it returns can be used to obtain information
// about the underlying operating system process.
//
// On Unix systems, FindProcess always succeeds and returns a Process
// for the given pid, regardless of whether the process exists.
func FindProcess(pid int) (*Process, error) {
return findProcess(pid)
}
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
//
// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
//
// If there is an error, it will be of type *PathError.
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
return startProcess(name, argv, attr)
}
// Release releases any resources associated with the Process p,
// rendering it unusable in the future.
// Release only needs to be called if Wait is not.
func (p *Process) Release() error {
return p.release()
}
// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
return p.kill()
}
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
// Signal sends a signal to the Process.
// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
return p.signal(sig)
}
// UserTime returns the user CPU time of the exited process and its children.
func (p *ProcessState) UserTime() time.Duration {
return p.userTime()
}
// SystemTime returns the system CPU time of the exited process and its children.
func (p *ProcessState) SystemTime() time.Duration {
return p.systemTime()
}
// Exited reports whether the program has exited.
func (p *ProcessState) Exited() bool {
return p.exited()
}
// Success reports whether the program exited successfully,
// such as with exit status 0 on Unix.
func (p *ProcessState) Success() bool {
return p.success()
}
// Sys returns system-dependent exit information about
// the process. Convert it to the appropriate underlying
// type, such as syscall.WaitStatus on Unix, to access its contents.
func (p *ProcessState) Sys() interface{} {
return p.sys()
}
// SysUsage returns system-dependent resource usage information about
// the exited process. Convert it to the appropriate underlying
// type, such as *syscall.Rusage on Unix, to access its contents.
// (On Unix, *syscall.Rusage matches struct rusage as defined in the
// getrusage(2) manual page.)
func (p *ProcessState) SysUsage() interface{} {
return p.sysUsage()
}
......@@ -11,10 +11,6 @@ import (
"syscall"
)
func sameFile(fs1, fs2 *fileStat) bool {
return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
}
func rename(oldname, newname string) error {
e := syscall.Rename(oldname, newname)
if e != nil {
......@@ -147,69 +143,6 @@ func (file *file) close() error {
return err
}
// Stat returns the FileInfo structure describing file.
// If there is an error, it will be of type *PathError.
func (f *File) Stat() (FileInfo, error) {
if f == nil {
return nil, ErrInvalid
}
var fs fileStat
err := syscall.Fstat(f.fd, &fs.sys)
if err != nil {
return nil, &PathError{"stat", f.name, err}
}
fillFileStatFromSys(&fs, f.name)
return &fs, nil
}
// 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) {
var fs fileStat
err := syscall.Stat(name, &fs.sys)
if err != nil {
return nil, &PathError{"stat", name, err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}
// 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) {
var fs fileStat
err := syscall.Lstat(name, &fs.sys)
if err != nil {
return nil, &PathError{"lstat", name, err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}
func (f *File) readdir(n int) (fi []FileInfo, err error) {
dirname := f.name
if dirname == "" {
dirname = "."
}
names, err := f.Readdirnames(n)
fi = make([]FileInfo, 0, len(names))
for _, filename := range names {
fip, lerr := lstat(dirname + "/" + filename)
if IsNotExist(lerr) {
// File disappeared between readdir + stat.
// Just treat it as if it didn't exist.
continue
}
if lerr != nil {
return fi, lerr
}
fi = append(fi, fip)
}
return fi, err
}
// Darwin and FreeBSD can't read or write 2GB+ at a time,
// even on 64-bit systems. See golang.org/issue/7812.
// Use 1GB instead of, say, 2GB-1, to keep subsequent
......@@ -324,24 +257,6 @@ func Remove(name string) error {
return &PathError{"remove", name, e}
}
// 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
}
// TempDir returns the default directory to use for temporary files.
func TempDir() string {
dir := Getenv("TMPDIR")
......
......@@ -196,65 +196,6 @@ func (file *file) close() error {
return err
}
func (file *File) readdir(n int) (fi []FileInfo, err error) {
if file == nil {
return nil, syscall.EINVAL
}
if !file.isdir() {
return nil, &PathError{"Readdir", file.name, syscall.ENOTDIR}
}
if !file.dirinfo.isempty && file.fd == syscall.InvalidHandle {
return nil, syscall.EINVAL
}
wantAll := n <= 0
size := n
if wantAll {
n = -1
size = 100
}
fi = make([]FileInfo, 0, size) // Empty with room to grow.
d := &file.dirinfo.data
for n != 0 && !file.dirinfo.isempty {
if file.dirinfo.needdata {
e := syscall.FindNextFile(file.fd, d)
if e != nil {
if e == syscall.ERROR_NO_MORE_FILES {
break
} else {
err = &PathError{"FindNextFile", file.name, e}
if !wantAll {
fi = nil
}
return
}
}
}
file.dirinfo.needdata = true
name := syscall.UTF16ToString(d.FileName[0:])
if name == "." || name == ".." { // Useless names
continue
}
f := &fileStat{
name: name,
sys: syscall.Win32FileAttributeData{
FileAttributes: d.FileAttributes,
CreationTime: d.CreationTime,
LastAccessTime: d.LastAccessTime,
LastWriteTime: d.LastWriteTime,
FileSizeHigh: d.FileSizeHigh,
FileSizeLow: d.FileSizeLow,
},
path: file.dirinfo.path + `\` + name,
}
n--
fi = append(fi, f)
}
if !wantAll && len(fi) == 0 {
return fi, io.EOF
}
return fi, nil
}
// readConsole reads utf16 characters from console File,
// encodes them into utf8 and stores them in buffer b.
// It returns the number of utf8 bytes read and an error, if any.
......@@ -586,42 +527,3 @@ func Symlink(oldname, newname string) error {
}
return nil
}
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
}
......@@ -15,3 +15,21 @@ const (
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
}
......@@ -14,3 +14,116 @@ 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
}
......@@ -11,12 +11,6 @@ import (
const _BIT16SZ = 2
func sameFile(fs1, fs2 *fileStat) bool {
a := fs1.sys.(*syscall.Dir)
b := fs2.sys.(*syscall.Dir)
return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
}
func fileInfoFromStat(d *syscall.Dir) FileInfo {
fs := &fileStat{
name: d.Name,
......
// 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.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package os
import (
"syscall"
)
// Stat returns the FileInfo structure describing file.
// If there is an error, it will be of type *PathError.
func (f *File) Stat() (FileInfo, error) {
if f == nil {
return nil, ErrInvalid
}
var fs fileStat
err := syscall.Fstat(f.fd, &fs.sys)
if err != nil {
return nil, &PathError{"stat", f.name, err}
}
fillFileStatFromSys(&fs, f.name)
return &fs, nil
}
// 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) {
var fs fileStat
err := syscall.Stat(name, &fs.sys)
if err != nil {
return nil, &PathError{"stat", name, err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}
// 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) {
var fs fileStat
err := syscall.Lstat(name, &fs.sys)
if err != nil {
return nil, &PathError{"lstat", name, err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}
......@@ -105,77 +105,3 @@ func Lstat(name string) (FileInfo, error) {
}
return fs, nil
}
// 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 ""
}
// Copyright 2012 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
// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err error) {
return hostname()
}
......@@ -4,7 +4,10 @@
package os
import "time"
import (
"syscall"
"time"
)
// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
type fileStat struct {
......@@ -19,3 +22,9 @@ 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 {
a := fs1.sys.(*syscall.Dir)
b := fs2.sys.(*syscall.Dir)
return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
}
......@@ -25,3 +25,7 @@ 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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment