github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/vfs/rand_suffix.go (about) 1 package vfs 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 "strings" 8 "sync" 9 "time" 10 ) 11 12 // Code taken from io/ioutil go package 13 14 // Random number state. 15 // We generate random temporary file names so that there's a good 16 // chance the file doesn't exist yet - keeps the number of tries in 17 // TempFile to a minimum. 18 var rand uint32 19 var randmu sync.Mutex 20 21 func nextSuffix() string { 22 randmu.Lock() 23 r := rand 24 if r == 0 { 25 r = reseed() 26 } 27 r = r*1664525 + 1013904223 // constants from Numerical Recipes 28 rand = r 29 randmu.Unlock() 30 return strconv.Itoa(int(1e9 + r%1e9))[1:] 31 } 32 33 func reseed() uint32 { 34 return uint32(time.Now().UnixNano() + int64(os.Getpid())) 35 } 36 37 // tryOrUseSuffix will try the given function until it succeed without 38 // an os.ErrExist error. It is used for renaming safely a file without 39 // collision. 40 func tryOrUseSuffix(name, format string, do func(suffix string) error) error { 41 var err error 42 nconflict := 0 43 for i := 0; i < 1000; i++ { 44 var newname string 45 if i == 0 { 46 newname = name 47 } else { 48 newname = fmt.Sprintf(format, name, nextSuffix()) 49 } 50 err = do(newname) 51 if !os.IsExist(err) { 52 break 53 } 54 if nconflict++; nconflict > 10 { 55 randmu.Lock() 56 rand = reseed() 57 randmu.Unlock() 58 } 59 } 60 return err 61 } 62 63 func stripConflictSuffix(name string) string { 64 loc := strings.LastIndex(name, "(") 65 if loc <= 0 { 66 return name 67 } 68 for i := loc; i < len(name); i++ { 69 switch name[i] { 70 case '(', ')', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 71 // OK 72 default: 73 return name 74 } 75 } 76 return name[:loc-1] 77 }