Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/go/internal/lockedfile/lockedfile_filelock.go

Documentation: cmd/go/internal/lockedfile

     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  // +build !plan9
     7  
     8  package lockedfile
     9  
    10  import (
    11  	"io/fs"
    12  	"os"
    13  
    14  	"cmd/go/internal/lockedfile/internal/filelock"
    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 = filelock.Lock(f)
    31  	default:
    32  		err = filelock.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  				filelock.Unlock(f)
    47  				f.Close()
    48  				return nil, err
    49  			}
    50  		}
    51  	}
    52  
    53  	return f, nil
    54  }
    55  
    56  func closeFile(f *os.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 := filelock.Unlock(f)
    61  
    62  	if closeErr := f.Close(); err == nil {
    63  		err = closeErr
    64  	}
    65  	return err
    66  }
    67  

View as plain text