github.com/searKing/golang/go@v1.2.117/sync/filelock/lockedfile_filelock.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build !plan9 6 7 // Copied from go/gc/src/cmd/go/internal/lockedfile/lockedfile_filelock.go 8 9 package filelock 10 11 import ( 12 "io" 13 "io/fs" 14 "os" 15 ) 16 17 func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { 18 // On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile 19 // call instead of locking separately, but we have to support separate locking 20 // calls for Linux and Windows anyway, so it's simpler to use that approach 21 // consistently. 22 23 f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm) 24 if err != nil { 25 return nil, err 26 } 27 28 switch flag & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) { 29 case os.O_WRONLY, os.O_RDWR: 30 err = Lock(f) 31 default: 32 err = RLock(f) 33 } 34 if err != nil { 35 f.Close() 36 return nil, err 37 } 38 39 if flag&os.O_TRUNC == os.O_TRUNC { 40 if err := f.Truncate(0); err != nil { 41 // The documentation for os.O_TRUNC says “if possible, truncate file when 42 // opened”, but doesn't define “possible” (golang.org/issue/28699). 43 // We'll treat regular files (and symlinks to regular files) as “possible” 44 // and ignore errors for the rest. 45 if fi, statErr := f.Stat(); statErr != nil || fi.Mode().IsRegular() { 46 Unlock(f) 47 f.Close() 48 return nil, err 49 } 50 } 51 } 52 53 return f, nil 54 } 55 56 func closeFile(f File) error { 57 // Since locking syscalls operate on file descriptors, we must unlock the file 58 // while the descriptor is still valid — that is, before the file is closed — 59 // and avoid unlocking files that are already closed. 60 err := Unlock(f) 61 62 if f, ok := f.(io.Closer); ok { 63 if closeErr := f.Close(); err == nil { 64 err = closeErr 65 } 66 } 67 return err 68 }