forked from TrueCloudLab/rclone
lib/file: reimplement os.OpenFile allowing rename/delete open files under Windows
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.
This commit is contained in:
parent
571b4c060b
commit
42d997f639
4 changed files with 257 additions and 0 deletions
66
lib/file/file_windows.go
Normal file
66
lib/file/file_windows.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
//+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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue