git.codewithbenjii.xyz/Benji/tail@v0.0.0-20231001071248-540d26238f40/winfile/winfile.go (about)

     1  // Copyright (c) 2019 FOSS contributors of https://git.codewithbenjii.xyz/Benji/tail
     2  //go:build windows
     3  // +build windows
     4  
     5  package winfile
     6  
     7  import (
     8  	"os"
     9  	"syscall"
    10  	"unsafe"
    11  )
    12  
    13  // issue also described here
    14  //https://codereview.appspot.com/8203043/
    15  
    16  // https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L218
    17  func Open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
    18  	if len(path) == 0 {
    19  		return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
    20  	}
    21  	pathp, err := syscall.UTF16PtrFromString(path)
    22  	if err != nil {
    23  		return syscall.InvalidHandle, err
    24  	}
    25  	var access uint32
    26  	switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
    27  	case syscall.O_RDONLY:
    28  		access = syscall.GENERIC_READ
    29  	case syscall.O_WRONLY:
    30  		access = syscall.GENERIC_WRITE
    31  	case syscall.O_RDWR:
    32  		access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
    33  	}
    34  	if mode&syscall.O_CREAT != 0 {
    35  		access |= syscall.GENERIC_WRITE
    36  	}
    37  	if mode&syscall.O_APPEND != 0 {
    38  		access &^= syscall.GENERIC_WRITE
    39  		access |= syscall.FILE_APPEND_DATA
    40  	}
    41  	sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
    42  	var sa *syscall.SecurityAttributes
    43  	if mode&syscall.O_CLOEXEC == 0 {
    44  		sa = makeInheritSa()
    45  	}
    46  	var createmode uint32
    47  	switch {
    48  	case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
    49  		createmode = syscall.CREATE_NEW
    50  	case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
    51  		createmode = syscall.CREATE_ALWAYS
    52  	case mode&syscall.O_CREAT == syscall.O_CREAT:
    53  		createmode = syscall.OPEN_ALWAYS
    54  	case mode&syscall.O_TRUNC == syscall.O_TRUNC:
    55  		createmode = syscall.TRUNCATE_EXISTING
    56  	default:
    57  		createmode = syscall.OPEN_EXISTING
    58  	}
    59  	h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
    60  	return h, e
    61  }
    62  
    63  // https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L211
    64  func makeInheritSa() *syscall.SecurityAttributes {
    65  	var sa syscall.SecurityAttributes
    66  	sa.Length = uint32(unsafe.Sizeof(sa))
    67  	sa.InheritHandle = 1
    68  	return &sa
    69  }
    70  
    71  // https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_windows.go#L133
    72  func OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
    73  	r, e := Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
    74  	if e != nil {
    75  		return nil, e
    76  	}
    77  	return os.NewFile(uintptr(r), name), nil
    78  }
    79  
    80  // https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_posix.go#L61
    81  func syscallMode(i os.FileMode) (o uint32) {
    82  	o |= uint32(i.Perm())
    83  	if i&os.ModeSetuid != 0 {
    84  		o |= syscall.S_ISUID
    85  	}
    86  	if i&os.ModeSetgid != 0 {
    87  		o |= syscall.S_ISGID
    88  	}
    89  	if i&os.ModeSticky != 0 {
    90  		o |= syscall.S_ISVTX
    91  	}
    92  	// No mapping for Go's ModeTemporary (plan9 only).
    93  	return
    94  }