github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/os/stat_windows.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os
     6  
     7  import (
     8  	"syscall"
     9  	"unsafe"
    10  )
    11  
    12  // Stat returns the FileInfo structure describing file.
    13  // If there is an error, it will be of type *PathError.
    14  func (file *File) Stat() (fi FileInfo, err error) {
    15  	if file == nil {
    16  		return nil, ErrInvalid
    17  	}
    18  	if file == nil || file.fd < 0 {
    19  		return nil, syscall.EINVAL
    20  	}
    21  	if file.isdir() {
    22  		// I don't know any better way to do that for directory
    23  		return Stat(file.name)
    24  	}
    25  	if file.name == DevNull {
    26  		return &devNullStat, nil
    27  	}
    28  	var d syscall.ByHandleFileInformation
    29  	e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &d)
    30  	if e != nil {
    31  		return nil, &PathError{"GetFileInformationByHandle", file.name, e}
    32  	}
    33  	return &fileStat{
    34  		name: basename(file.name),
    35  		sys: syscall.Win32FileAttributeData{
    36  			FileAttributes: d.FileAttributes,
    37  			CreationTime:   d.CreationTime,
    38  			LastAccessTime: d.LastAccessTime,
    39  			LastWriteTime:  d.LastWriteTime,
    40  			FileSizeHigh:   d.FileSizeHigh,
    41  			FileSizeLow:    d.FileSizeLow,
    42  		},
    43  		vol:   d.VolumeSerialNumber,
    44  		idxhi: d.FileIndexHigh,
    45  		idxlo: d.FileIndexLow,
    46  	}, nil
    47  }
    48  
    49  // Stat returns a FileInfo structure describing the named file.
    50  // If there is an error, it will be of type *PathError.
    51  func Stat(name string) (fi FileInfo, err error) {
    52  	if len(name) == 0 {
    53  		return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
    54  	}
    55  	if name == DevNull {
    56  		return &devNullStat, nil
    57  	}
    58  	fs := &fileStat{name: basename(name)}
    59  	namep, e := syscall.UTF16PtrFromString(name)
    60  	if e != nil {
    61  		return nil, &PathError{"Stat", name, e}
    62  	}
    63  	e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys)))
    64  	if e != nil {
    65  		return nil, &PathError{"GetFileAttributesEx", name, e}
    66  	}
    67  	fs.path = name
    68  	if !isAbs(fs.path) {
    69  		cwd, _ := Getwd()
    70  		fs.path = cwd + `\` + fs.path
    71  	}
    72  	return fs, nil
    73  }
    74  
    75  // Lstat returns the FileInfo structure describing the named file.
    76  // If the file is a symbolic link, the returned FileInfo
    77  // describes the symbolic link.  Lstat makes no attempt to follow the link.
    78  // If there is an error, it will be of type *PathError.
    79  func Lstat(name string) (fi FileInfo, err error) {
    80  	// No links on Windows
    81  	return Stat(name)
    82  }
    83  
    84  // basename removes trailing slashes and the leading
    85  // directory name and drive letter from path name.
    86  func basename(name string) string {
    87  	// Remove drive letter
    88  	if len(name) == 2 && name[1] == ':' {
    89  		name = "."
    90  	} else if len(name) > 2 && name[1] == ':' {
    91  		name = name[2:]
    92  	}
    93  	i := len(name) - 1
    94  	// Remove trailing slashes
    95  	for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
    96  		name = name[:i]
    97  	}
    98  	// Remove leading directory name
    99  	for i--; i >= 0; i-- {
   100  		if name[i] == '/' || name[i] == '\\' {
   101  			name = name[i+1:]
   102  			break
   103  		}
   104  	}
   105  	return name
   106  }
   107  
   108  func isSlash(c uint8) bool {
   109  	return c == '\\' || c == '/'
   110  }
   111  
   112  func isAbs(path string) (b bool) {
   113  	v := volumeName(path)
   114  	if v == "" {
   115  		return false
   116  	}
   117  	path = path[len(v):]
   118  	if path == "" {
   119  		return false
   120  	}
   121  	return isSlash(path[0])
   122  }
   123  
   124  func volumeName(path string) (v string) {
   125  	if len(path) < 2 {
   126  		return ""
   127  	}
   128  	// with drive letter
   129  	c := path[0]
   130  	if path[1] == ':' &&
   131  		('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
   132  			'A' <= c && c <= 'Z') {
   133  		return path[:2]
   134  	}
   135  	// is it UNC
   136  	if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
   137  		!isSlash(path[2]) && path[2] != '.' {
   138  		// first, leading `\\` and next shouldn't be `\`. its server name.
   139  		for n := 3; n < l-1; n++ {
   140  			// second, next '\' shouldn't be repeated.
   141  			if isSlash(path[n]) {
   142  				n++
   143  				// third, following something characters. its share name.
   144  				if !isSlash(path[n]) {
   145  					if path[n] == '.' {
   146  						break
   147  					}
   148  					for ; n < l; n++ {
   149  						if isSlash(path[n]) {
   150  							break
   151  						}
   152  					}
   153  					return path[:n]
   154  				}
   155  				break
   156  			}
   157  		}
   158  	}
   159  	return ""
   160  }