github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/client/logging/stat_windows.go (about)

     1  package logging
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"runtime"
     7  	"syscall" //nolint:depguard // We specifically need "syscall.Win32FileAttributeData" rather than "windows.Win32FileAttributeData" for fs.File.Sys().
     8  	"time"
     9  
    10  	"github.com/hectane/go-acl/api"
    11  	"golang.org/x/sys/windows"
    12  
    13  	"github.com/telepresenceio/telepresence/v2/pkg/dos"
    14  )
    15  
    16  type WindowsSysInfo interface {
    17  	SysInfo
    18  	Owner() *windows.SID
    19  	Group() *windows.SID
    20  	DACL() windows.Handle
    21  	SACL() windows.Handle
    22  	SecurityDescriptor() windows.Handle
    23  }
    24  
    25  type windowsSysInfo struct {
    26  	path    string
    27  	data    *syscall.Win32FileAttributeData
    28  	owner   *windows.SID
    29  	group   *windows.SID
    30  	dacl    windows.Handle
    31  	sacl    windows.Handle
    32  	secDesc windows.Handle
    33  }
    34  
    35  func osFStat(file dos.File) (SysInfo, error) {
    36  	info, err := file.Stat()
    37  	if err != nil {
    38  		return nil, fmt.Errorf("failed to stat %s: %w", file.Name(), err)
    39  	}
    40  	sys, ok := info.Sys().(*syscall.Win32FileAttributeData)
    41  	if !ok {
    42  		return nil, fmt.Errorf("files of type %T don't support Fstat", file)
    43  	}
    44  	wi := windowsSysInfo{
    45  		path: file.Name(),
    46  		data: sys,
    47  	}
    48  	err = api.GetNamedSecurityInfo(
    49  		wi.path,
    50  		api.SE_FILE_OBJECT,
    51  		api.OWNER_SECURITY_INFORMATION,
    52  		&wi.owner,
    53  		&wi.group,
    54  		&wi.dacl,
    55  		&wi.sacl,
    56  		&wi.secDesc,
    57  	)
    58  	if err != nil && !errors.Is(err, windows.ERROR_SUCCESS) {
    59  		return nil, err
    60  	}
    61  	runtime.SetFinalizer(&wi, func(wi *windowsSysInfo) {
    62  		_, _ = windows.LocalFree(wi.secDesc)
    63  	})
    64  	return &wi, nil
    65  }
    66  
    67  func (wi *windowsSysInfo) Size() int64 {
    68  	return int64(wi.data.FileSizeHigh)<<32 + int64(wi.data.FileSizeLow)
    69  }
    70  
    71  func (wi *windowsSysInfo) SetOwnerAndGroup(name string) error {
    72  	err := api.SetNamedSecurityInfo(name, api.SE_FILE_OBJECT, api.OWNER_SECURITY_INFORMATION, wi.owner, wi.group, wi.dacl, wi.sacl)
    73  	if err != nil {
    74  		// On some systems it seems SetNamedSecurityInfo will return ERROR_SUCCESS on success... this is an odd violation of the principle
    75  		// that windows APIs return err = nil on success but okay
    76  		if errors.Is(err, windows.ERROR_SUCCESS) {
    77  			return nil
    78  		}
    79  		return err
    80  	}
    81  	return nil
    82  }
    83  
    84  func (wi *windowsSysInfo) HaveSameOwnerAndGroup(s SysInfo) bool {
    85  	eq := func(a, b *windows.SID) bool {
    86  		if a == b {
    87  			return true
    88  		}
    89  		if a == nil || b == nil {
    90  			return false
    91  		}
    92  		if a.IsValid() {
    93  			if b.IsValid() {
    94  				return a.Equals(b)
    95  			}
    96  			return false
    97  		}
    98  		return !b.IsValid()
    99  	}
   100  	owi, ok := s.(*windowsSysInfo)
   101  	return ok && eq(wi.owner, owi.owner) && eq(wi.group, owi.group)
   102  }
   103  
   104  func (wi *windowsSysInfo) BirthTime() time.Time {
   105  	return time.Unix(0, wi.data.CreationTime.Nanoseconds())
   106  }
   107  
   108  func (wi *windowsSysInfo) ModifyTime() time.Time {
   109  	return time.Unix(0, wi.data.LastWriteTime.Nanoseconds())
   110  }
   111  
   112  func (wi *windowsSysInfo) ChangeTime() time.Time {
   113  	return time.Unix(0, wi.data.LastWriteTime.Nanoseconds())
   114  }
   115  
   116  func (wi *windowsSysInfo) Owner() *windows.SID {
   117  	return wi.owner
   118  }
   119  
   120  func (wi *windowsSysInfo) Group() *windows.SID {
   121  	return wi.group
   122  }
   123  
   124  func (wi *windowsSysInfo) DACL() windows.Handle {
   125  	return wi.dacl
   126  }
   127  
   128  func (wi *windowsSysInfo) SACL() windows.Handle {
   129  	return wi.sacl
   130  }
   131  
   132  func (wi *windowsSysInfo) String() string {
   133  	ov := "invalid"
   134  	if wi.owner != nil && wi.owner.IsValid() {
   135  		ov = wi.owner.String()
   136  	}
   137  	gv := "invalid"
   138  	if wi.group != nil && wi.group.IsValid() {
   139  		gv = wi.group.String()
   140  	}
   141  	return fmt.Sprintf("CTIME %v, UID %v, GID %v", wi.BirthTime(), ov, gv)
   142  }