94 lines · 2.4 KB · Go
RawDownload
// 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 uint32var 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}