Home | History | Annotate | Download | only in os
      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 	"sync"
      9 	"syscall"
     10 	"time"
     11 )
     12 
     13 // A fileStat is the implementation of FileInfo returned by Stat and Lstat.
     14 type fileStat struct {
     15 	name string
     16 	sys  syscall.Win32FileAttributeData
     17 	pipe bool
     18 
     19 	// used to implement SameFile
     20 	sync.Mutex
     21 	path  string
     22 	vol   uint32
     23 	idxhi uint32
     24 	idxlo uint32
     25 }
     26 
     27 func (fs *fileStat) Size() int64 {
     28 	return int64(fs.sys.FileSizeHigh)<<32 + int64(fs.sys.FileSizeLow)
     29 }
     30 
     31 func (fs *fileStat) Mode() (m FileMode) {
     32 	if fs == &devNullStat {
     33 		return ModeDevice | ModeCharDevice | 0666
     34 	}
     35 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
     36 		m |= ModeDir | 0111
     37 	}
     38 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
     39 		m |= 0444
     40 	} else {
     41 		m |= 0666
     42 	}
     43 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
     44 		m |= ModeSymlink
     45 	}
     46 	if fs.pipe {
     47 		m |= ModeNamedPipe
     48 	}
     49 	return m
     50 }
     51 
     52 func (fs *fileStat) ModTime() time.Time {
     53 	return time.Unix(0, fs.sys.LastWriteTime.Nanoseconds())
     54 }
     55 
     56 // Sys returns syscall.Win32FileAttributeData for file fs.
     57 func (fs *fileStat) Sys() interface{} { return &fs.sys }
     58 
     59 func (fs *fileStat) loadFileId() error {
     60 	fs.Lock()
     61 	defer fs.Unlock()
     62 	if fs.path == "" {
     63 		// already done
     64 		return nil
     65 	}
     66 	pathp, err := syscall.UTF16PtrFromString(fs.path)
     67 	if err != nil {
     68 		return err
     69 	}
     70 	h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
     71 	if err != nil {
     72 		return err
     73 	}
     74 	defer syscall.CloseHandle(h)
     75 	var i syscall.ByHandleFileInformation
     76 	err = syscall.GetFileInformationByHandle(h, &i)
     77 	if err != nil {
     78 		return err
     79 	}
     80 	fs.path = ""
     81 	fs.vol = i.VolumeSerialNumber
     82 	fs.idxhi = i.FileIndexHigh
     83 	fs.idxlo = i.FileIndexLow
     84 	return nil
     85 }
     86 
     87 // devNullStat is fileStat structure describing DevNull file ("NUL").
     88 var devNullStat = fileStat{
     89 	name: DevNull,
     90 	// hopefully this will work for SameFile
     91 	vol:   0,
     92 	idxhi: 0,
     93 	idxlo: 0,
     94 }
     95 
     96 func sameFile(fs1, fs2 *fileStat) bool {
     97 	e := fs1.loadFileId()
     98 	if e != nil {
     99 		return false
    100 	}
    101 	e = fs2.loadFileId()
    102 	if e != nil {
    103 		return false
    104 	}
    105 	return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo
    106 }
    107 
    108 // For testing.
    109 func atime(fi FileInfo) time.Time {
    110 	return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
    111 }
    112