mirror of
https://github.com/rclone/rclone
synced 2024-10-31 20:16:42 +01:00
42d997f639
Normally os.OpenFile under Windows does not allow renaming or deleting open file handles. This package provides equivelents for os.OpenFile, os.Open and os.Create which do allow that.
67 lines
2.2 KiB
Go
67 lines
2.2 KiB
Go
//+build windows
|
|
|
|
package file
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
)
|
|
|
|
// OpenFile is the generalized open call; most users will use Open or Create
|
|
// instead. It opens the named file with specified flag (O_RDONLY etc.) and
|
|
// perm (before umask), if applicable. If successful, methods on the returned
|
|
// File can be used for I/O. If there is an error, it will be of type
|
|
// *PathError.
|
|
//
|
|
// Under both Unix and Windows this will allow open files to be
|
|
// renamed and or deleted.
|
|
func OpenFile(path string, mode int, perm os.FileMode) (*os.File, error) {
|
|
// This code copied from syscall_windows.go in the go source and then
|
|
// modified to support renaming and deleting open files by adding
|
|
// FILE_SHARE_DELETE.
|
|
//
|
|
// https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea#file_share_delete
|
|
if len(path) == 0 {
|
|
return nil, syscall.ERROR_FILE_NOT_FOUND
|
|
}
|
|
pathp, err := syscall.UTF16PtrFromString(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var access uint32
|
|
switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
|
|
case syscall.O_RDONLY:
|
|
access = syscall.GENERIC_READ
|
|
case syscall.O_WRONLY:
|
|
access = syscall.GENERIC_WRITE
|
|
case syscall.O_RDWR:
|
|
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
|
|
}
|
|
if mode&syscall.O_CREAT != 0 {
|
|
access |= syscall.GENERIC_WRITE
|
|
}
|
|
if mode&syscall.O_APPEND != 0 {
|
|
access &^= syscall.GENERIC_WRITE
|
|
access |= syscall.FILE_APPEND_DATA
|
|
}
|
|
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
|
|
var createmode uint32
|
|
switch {
|
|
case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
|
|
createmode = syscall.CREATE_NEW
|
|
case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
|
|
createmode = syscall.CREATE_ALWAYS
|
|
case mode&syscall.O_CREAT == syscall.O_CREAT:
|
|
createmode = syscall.OPEN_ALWAYS
|
|
case mode&syscall.O_TRUNC == syscall.O_TRUNC:
|
|
createmode = syscall.TRUNCATE_EXISTING
|
|
default:
|
|
createmode = syscall.OPEN_EXISTING
|
|
}
|
|
h, e := syscall.CreateFile(pathp, access, sharemode, nil, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
return os.NewFile(uintptr(h), path), nil
|
|
}
|