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 }