mirror of
https://github.com/rclone/rclone.git
synced 2024-11-26 02:09:55 +08:00
95 lines
2.4 KiB
Go
95 lines
2.4 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved. Use of this source code
|
|
// is governed by a BSD-style license that can be found in the LICENSE.golang
|
|
// file.
|
|
//
|
|
// This is a copied and modified version of the code provided in:
|
|
// https://golang.org/src/io/ioutil/tempfile.go
|
|
|
|
package tmpfile
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// Random number state.
|
|
// We generate random temporary file names so that there's a good
|
|
// chance the file doesn't exist yet - keeps the number of tries in
|
|
// TempFile to a minimum.
|
|
var rand uint32
|
|
var randmu sync.Mutex
|
|
|
|
func reseed() uint32 {
|
|
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
|
}
|
|
|
|
func nextRandom() string {
|
|
randmu.Lock()
|
|
r := rand
|
|
if r == 0 {
|
|
r = reseed()
|
|
}
|
|
r = r*1664525 + 1013904223 // constants from Numerical Recipes
|
|
rand = r
|
|
randmu.Unlock()
|
|
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
|
}
|
|
|
|
// New creates a new temporary file in the directory dir using the same method
|
|
// as ioutil.TempFile and then unlinks the file with os.Remove to ensure the
|
|
// file is deleted when the calling process exists.
|
|
func New(dir, pattern string) (f *os.File, err error) {
|
|
if dir == "" {
|
|
dir = os.TempDir()
|
|
}
|
|
|
|
var prefix, suffix string
|
|
if pos := strings.LastIndex(pattern, "*"); pos != -1 {
|
|
prefix, suffix = pattern[:pos], pattern[pos+1:]
|
|
} else {
|
|
prefix = pattern
|
|
}
|
|
|
|
nconflict := 0
|
|
for i := 0; i < 10000; i++ {
|
|
name := filepath.Join(dir, prefix+nextRandom()+suffix)
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
|
|
handle, err := windows.CreateFile(
|
|
windows.StringToUTF16Ptr(name), // File Name
|
|
windows.GENERIC_READ|windows.GENERIC_WRITE|windows.DELETE, // Desired Access
|
|
windows.FILE_SHARE_DELETE, // Share Mode
|
|
nil, // Security Attributes
|
|
windows.CREATE_NEW, // Create Disposition
|
|
windows.FILE_ATTRIBUTE_TEMPORARY|windows.FILE_FLAG_DELETE_ON_CLOSE, // Flags & Attributes
|
|
0, // Template File
|
|
)
|
|
if os.IsExist(err) {
|
|
if nconflict++; nconflict > 10 {
|
|
randmu.Lock()
|
|
rand = reseed()
|
|
randmu.Unlock()
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
f = os.NewFile(uintptr(handle), name)
|
|
|
|
break
|
|
}
|
|
|
|
err = os.Remove(f.Name())
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return f, nil
|
|
}
|