github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/lockedfile/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 // +build !plan9 6 7 package lockedfile 8 9 import ( 10 "os" 11 12 "github.com/gagliardetto/golang-go/cmd/go/not-internal/lockedfile/internal/filelock" 13 ) 14 15 func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { 16 // On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile 17 // call instead of locking separately, but we have to support separate locking 18 // calls for Linux and Windows anyway, so it's simpler to use that approach 19 // consistently. 20 21 f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm) 22 if err != nil { 23 return nil, err 24 } 25 26 switch flag & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) { 27 case os.O_WRONLY, os.O_RDWR: 28 err = filelock.Lock(f) 29 default: 30 err = filelock.RLock(f) 31 } 32 if err != nil { 33 f.Close() 34 return nil, err 35 } 36 37 if flag&os.O_TRUNC == os.O_TRUNC { 38 if err := f.Truncate(0); err != nil { 39 // The documentation for os.O_TRUNC says “if possible, truncate file when 40 // opened”, but doesn't define “possible” (golang.org/issue/28699). 41 // We'll treat regular files (and symlinks to regular files) as “possible” 42 // and ignore errors for the rest. 43 if fi, statErr := f.Stat(); statErr != nil || fi.Mode().IsRegular() { 44 filelock.Unlock(f) 45 f.Close() 46 return nil, err 47 } 48 } 49 } 50 51 return f, nil 52 } 53 54 func closeFile(f *os.File) error { 55 // Since locking syscalls operate on file descriptors, we must unlock the file 56 // while the descriptor is still valid — that is, before the file is closed — 57 // and avoid unlocking files that are already closed. 58 err := filelock.Unlock(f) 59 60 if closeErr := f.Close(); err == nil { 61 err = closeErr 62 } 63 return err 64 }