From: Hiroshi Ioka Date: Sun, 14 Aug 2016 16:39:00 +0000 (+0900) Subject: os: consolidate files X-Git-Tag: go1.8beta1~1891 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=664c4a1f87fb48d7af6880fd9e4b504049c37b9b;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/os/dir.go b/src/os/dir.go new file mode 100644 index 0000000000..6c54456a21 --- /dev/null +++ b/src/os/dir.go @@ -0,0 +1,46 @@ +// 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 + +// 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 +// further FileInfos. +// +// If n > 0, Readdir returns at most n FileInfo structures. In this case, if +// Readdir returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is io.EOF. +// +// If n <= 0, Readdir returns all the FileInfo from the directory in +// a single slice. In this case, if Readdir succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil error. If it encounters an error before the end of the +// directory, Readdir returns the FileInfo read until that point +// and a non-nil error. +func (f *File) Readdir(n int) ([]FileInfo, error) { + if f == nil { + return nil, ErrInvalid + } + return f.readdir(n) +} + +// Readdirnames reads and returns a slice of names from the directory f. +// +// If n > 0, Readdirnames returns at most n names. In this case, if +// Readdirnames returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is io.EOF. +// +// If n <= 0, Readdirnames returns all the names from the directory in +// a single slice. In this case, if Readdirnames succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil error. If it encounters an error before the end of the +// directory, Readdirnames returns the names read until that point and +// a non-nil error. +func (f *File) Readdirnames(n int) (names []string, err error) { + if f == nil { + return nil, ErrInvalid + } + return f.readdirnames(n) +} diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go index 589db85274..cfa70a141e 100644 --- a/src/os/dir_unix.go +++ b/src/os/dir_unix.go @@ -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 { diff --git a/src/os/dir_windows.go b/src/os/dir_windows.go index 931316048b..76024fc1e3 100644 --- a/src/os/dir_windows.go +++ b/src/os/dir_windows.go @@ -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)) diff --git a/src/os/doc.go b/src/os/doc.go deleted file mode 100644 index 0313eac234..0000000000 --- a/src/os/doc.go +++ /dev/null @@ -1,139 +0,0 @@ -// 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 - -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 -// further FileInfos. -// -// If n > 0, Readdir returns at most n FileInfo structures. In this case, if -// Readdir returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdir returns all the FileInfo from the directory in -// a single slice. In this case, if Readdir succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdir returns the FileInfo read until that point -// and a non-nil error. -func (f *File) Readdir(n int) ([]FileInfo, error) { - if f == nil { - return nil, ErrInvalid - } - return f.readdir(n) -} - -// Readdirnames reads and returns a slice of names from the directory f. -// -// If n > 0, Readdirnames returns at most n names. In this case, if -// Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdirnames returns all the names from the directory in -// a single slice. In this case, if Readdirnames succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdirnames returns the names read until that point and -// a non-nil error. -func (f *File) Readdirnames(n int) (names []string, err error) { - if f == nil { - return nil, ErrInvalid - } - return f.readdirnames(n) -} diff --git a/src/os/exec.go b/src/os/exec.go index bf3249864d..8a53e5dd1e 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -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() +} diff --git a/src/os/file_unix.go b/src/os/file_unix.go index 9b64f21650..5bc2b11622 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -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") diff --git a/src/os/file_windows.go b/src/os/file_windows.go index f470fc4315..722d4d0823 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -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 -} diff --git a/src/os/path_unix.go b/src/os/path_unix.go index 36f8e61bf9..ecf098c461 100644 --- a/src/os/path_unix.go +++ b/src/os/path_unix.go @@ -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 +} diff --git a/src/os/path_windows.go b/src/os/path_windows.go index c96f137686..ced28c3f0f 100644 --- a/src/os/path_windows.go +++ b/src/os/path_windows.go @@ -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 +} diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go index 96f056c111..1ae165807f 100644 --- a/src/os/stat_plan9.go +++ b/src/os/stat_plan9.go @@ -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, diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go new file mode 100644 index 0000000000..1733d3f132 --- /dev/null +++ b/src/os/stat_unix.go @@ -0,0 +1,52 @@ +// 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 +} diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go index e55eeb0fdd..3c433b1579 100644 --- a/src/os/stat_windows.go +++ b/src/os/stat_windows.go @@ -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 "" -} diff --git a/src/os/sys.go b/src/os/sys.go new file mode 100644 index 0000000000..28b0f6bab0 --- /dev/null +++ b/src/os/sys.go @@ -0,0 +1,10 @@ +// 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() +} diff --git a/src/os/types_plan9.go b/src/os/types_plan9.go index 6d46ca9dd3..5fccc4f09a 100644 --- a/src/os/types_plan9.go +++ b/src/os/types_plan9.go @@ -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 +} diff --git a/src/os/types_unix.go b/src/os/types_unix.go index 056220c09b..c0259ae0e8 100644 --- a/src/os/types_unix.go +++ b/src/os/types_unix.go @@ -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 +}