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  }