github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/lib/file/file_windows.go (about)

     1  //+build windows
     2  
     3  package file
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  )
     9  
    10  // OpenFile is the generalized open call; most users will use Open or Create
    11  // instead. It opens the named file with specified flag (O_RDONLY etc.) and
    12  // perm (before umask), if applicable. If successful, methods on the returned
    13  // File can be used for I/O. If there is an error, it will be of type
    14  // *PathError.
    15  //
    16  // Under both Unix and Windows this will allow open files to be
    17  // renamed and or deleted.
    18  func OpenFile(path string, mode int, perm os.FileMode) (*os.File, error) {
    19  	// This code copied from syscall_windows.go in the go source and then
    20  	// modified to support renaming and deleting open files by adding
    21  	// FILE_SHARE_DELETE.
    22  	//
    23  	// https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea#file_share_delete
    24  	if len(path) == 0 {
    25  		return nil, syscall.ERROR_FILE_NOT_FOUND
    26  	}
    27  	pathp, err := syscall.UTF16PtrFromString(path)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	var access uint32
    32  	switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
    33  	case syscall.O_RDONLY:
    34  		access = syscall.GENERIC_READ
    35  	case syscall.O_WRONLY:
    36  		access = syscall.GENERIC_WRITE
    37  	case syscall.O_RDWR:
    38  		access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
    39  	}
    40  	if mode&syscall.O_CREAT != 0 {
    41  		access |= syscall.GENERIC_WRITE
    42  	}
    43  	if mode&syscall.O_APPEND != 0 {
    44  		access &^= syscall.GENERIC_WRITE
    45  		access |= syscall.FILE_APPEND_DATA
    46  	}
    47  	sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
    48  	var createmode uint32
    49  	switch {
    50  	case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
    51  		createmode = syscall.CREATE_NEW
    52  	case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
    53  		createmode = syscall.CREATE_ALWAYS
    54  	case mode&syscall.O_CREAT == syscall.O_CREAT:
    55  		createmode = syscall.OPEN_ALWAYS
    56  	case mode&syscall.O_TRUNC == syscall.O_TRUNC:
    57  		createmode = syscall.TRUNCATE_EXISTING
    58  	default:
    59  		createmode = syscall.OPEN_EXISTING
    60  	}
    61  	h, e := syscall.CreateFile(pathp, access, sharemode, nil, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
    62  	if e != nil {
    63  		return nil, e
    64  	}
    65  	return os.NewFile(uintptr(h), path), nil
    66  }