github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/os/stat_plan9.go (about)

     1  // Copyright 2011 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  	"time"
    10  )
    11  
    12  func sameFile(fs1, fs2 *fileStat) bool {
    13  	a := fs1.sys.(*syscall.Dir)
    14  	b := fs2.sys.(*syscall.Dir)
    15  	return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
    16  }
    17  
    18  func fileInfoFromStat(d *syscall.Dir) FileInfo {
    19  	fs := &fileStat{
    20  		name:    d.Name,
    21  		size:    int64(d.Length),
    22  		modTime: time.Unix(int64(d.Mtime), 0),
    23  		sys:     d,
    24  	}
    25  	fs.mode = FileMode(d.Mode & 0777)
    26  	if d.Mode&syscall.DMDIR != 0 {
    27  		fs.mode |= ModeDir
    28  	}
    29  	if d.Mode&syscall.DMAPPEND != 0 {
    30  		fs.mode |= ModeAppend
    31  	}
    32  	if d.Mode&syscall.DMEXCL != 0 {
    33  		fs.mode |= ModeExclusive
    34  	}
    35  	if d.Mode&syscall.DMTMP != 0 {
    36  		fs.mode |= ModeTemporary
    37  	}
    38  	return fs
    39  }
    40  
    41  // arg is an open *File or a path string.
    42  func dirstat(arg interface{}) (*syscall.Dir, error) {
    43  	var name string
    44  
    45  	// This is big enough for most stat messages
    46  	// and rounded to a multiple of 128 bytes.
    47  	size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128
    48  
    49  	for i := 0; i < 2; i++ {
    50  		buf := make([]byte, size)
    51  
    52  		var n int
    53  		var err error
    54  		switch a := arg.(type) {
    55  		case *File:
    56  			name = a.name
    57  			n, err = syscall.Fstat(a.fd, buf)
    58  		case string:
    59  			name = a
    60  			n, err = syscall.Stat(a, buf)
    61  		default:
    62  			panic("phase error in dirstat")
    63  		}
    64  		if err != nil {
    65  			return nil, &PathError{"stat", name, err}
    66  		}
    67  		if n < syscall.STATFIXLEN {
    68  			return nil, &PathError{"stat", name, syscall.ErrShortStat}
    69  		}
    70  
    71  		// Pull the real size out of the stat message.
    72  		size = int(uint16(buf[0]) | uint16(buf[1])<<8)
    73  
    74  		// If the stat message is larger than our buffer we will
    75  		// go around the loop and allocate one that is big enough.
    76  		if size > n {
    77  			continue
    78  		}
    79  
    80  		d, err := syscall.UnmarshalDir(buf[:n])
    81  		if err != nil {
    82  			return nil, &PathError{"stat", name, err}
    83  		}
    84  		return d, nil
    85  	}
    86  	return nil, &PathError{"stat", name, syscall.ErrBadStat}
    87  }
    88  
    89  // Stat returns a FileInfo describing the named file.
    90  // If there is an error, it will be of type *PathError.
    91  func Stat(name string) (fi FileInfo, err error) {
    92  	d, err := dirstat(name)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return fileInfoFromStat(d), nil
    97  }
    98  
    99  // Lstat returns a FileInfo describing the named file.
   100  // If the file is a symbolic link, the returned FileInfo
   101  // describes the symbolic link.  Lstat makes no attempt to follow the link.
   102  // If there is an error, it will be of type *PathError.
   103  func Lstat(name string) (fi FileInfo, err error) {
   104  	return Stat(name)
   105  }
   106  
   107  // For testing.
   108  func atime(fi FileInfo) time.Time {
   109  	return time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0)
   110  }