Source file src/cmd/go/internal/work/shell_nonwindows.go

     1  // Copyright 2025 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 !windows
     6  
     7  package work
     8  
     9  import (
    10  	"errors"
    11  	"io/fs"
    12  	"os"
    13  	"path/filepath"
    14  )
    15  
    16  // move moves a file from src to dst setting the permissions
    17  // on the destination file to inherit the permissions from the
    18  // destination parent directory.
    19  func (sh *Shell) move(src, dst string, perm fs.FileMode) error {
    20  	// If the destination directory has the group sticky bit set,
    21  	// we have to copy the file to retain the correct permissions.
    22  	// https://golang.org/issue/18878
    23  	if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
    24  		if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 {
    25  			return errors.ErrUnsupported
    26  		}
    27  	}
    28  	// The perm argument is meant to be adjusted according to umask,
    29  	// but we don't know what the umask is.
    30  	// Create a dummy file to find out.
    31  	// This works even on systems like Plan 9 where the
    32  	// file mask computation incorporates other information.
    33  	mode := perm
    34  	f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
    35  	if err == nil {
    36  		fi, err := f.Stat()
    37  		if err == nil {
    38  			mode = fi.Mode() & 0777
    39  		}
    40  		name := f.Name()
    41  		f.Close()
    42  		os.Remove(name)
    43  	}
    44  
    45  	if err := os.Chmod(src, mode); err != nil {
    46  		return err
    47  	}
    48  	return os.Rename(src, dst)
    49  }
    50  

View as plain text