...

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

     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		"cmd/go/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	}
    65	

View as plain text