...

Source file src/github.com/containerd/continuity/fs/copy_unix.go

Documentation: github.com/containerd/continuity/fs

     1  //go:build darwin || freebsd || openbsd || netbsd || dragonfly || solaris
     2  // +build darwin freebsd openbsd netbsd dragonfly solaris
     3  
     4  /*
     5     Copyright The containerd Authors.
     6  
     7     Licensed under the Apache License, Version 2.0 (the "License");
     8     you may not use this file except in compliance with the License.
     9     You may obtain a copy of the License at
    10  
    11         http://www.apache.org/licenses/LICENSE-2.0
    12  
    13     Unless required by applicable law or agreed to in writing, software
    14     distributed under the License is distributed on an "AS IS" BASIS,
    15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16     See the License for the specific language governing permissions and
    17     limitations under the License.
    18  */
    19  
    20  package fs
    21  
    22  import (
    23  	"fmt"
    24  	"os"
    25  	"runtime"
    26  	"syscall"
    27  
    28  	"github.com/containerd/continuity/sysx"
    29  )
    30  
    31  func copyFileInfo(fi os.FileInfo, src, name string) error {
    32  	st := fi.Sys().(*syscall.Stat_t)
    33  	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
    34  		if os.IsPermission(err) {
    35  			// Normally if uid/gid are the same this would be a no-op, but some
    36  			// filesystems may still return EPERM... for instance NFS does this.
    37  			// In such a case, this is not an error.
    38  			if dstStat, err2 := os.Lstat(name); err2 == nil {
    39  				st2 := dstStat.Sys().(*syscall.Stat_t)
    40  				if st.Uid == st2.Uid && st.Gid == st2.Gid {
    41  					err = nil
    42  				}
    43  			}
    44  		}
    45  		if err != nil {
    46  			return fmt.Errorf("failed to chown %s: %w", name, err)
    47  		}
    48  	}
    49  
    50  	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
    51  		if err := os.Chmod(name, fi.Mode()); err != nil {
    52  			return fmt.Errorf("failed to chmod %s: %w", name, err)
    53  		}
    54  	}
    55  
    56  	if err := utimesNano(name, StatAtime(st), StatMtime(st)); err != nil {
    57  		return fmt.Errorf("failed to utime %s: %w", name, err)
    58  	}
    59  
    60  	return nil
    61  }
    62  
    63  func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error {
    64  	xattrKeys, err := sysx.LListxattr(src)
    65  	if err != nil {
    66  		if os.IsPermission(err) && runtime.GOOS == "darwin" {
    67  			// On darwin, character devices do not permit listing xattrs
    68  			return nil
    69  		}
    70  		e := fmt.Errorf("failed to list xattrs on %s: %w", src, err)
    71  		if errorHandler != nil {
    72  			e = errorHandler(dst, src, "", e)
    73  		}
    74  		return e
    75  	}
    76  	for _, xattr := range xattrKeys {
    77  		if _, exclude := excludes[xattr]; exclude {
    78  			continue
    79  		}
    80  		data, err := sysx.LGetxattr(src, xattr)
    81  		if err != nil {
    82  			e := fmt.Errorf("failed to get xattr %q on %s: %w", xattr, src, err)
    83  			if errorHandler != nil {
    84  				if e = errorHandler(dst, src, xattr, e); e == nil {
    85  					continue
    86  				}
    87  			}
    88  			return e
    89  		}
    90  		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
    91  			e := fmt.Errorf("failed to set xattr %q on %s: %w", xattr, dst, err)
    92  			if errorHandler != nil {
    93  				if e = errorHandler(dst, src, xattr, e); e == nil {
    94  					continue
    95  				}
    96  			}
    97  			return e
    98  		}
    99  	}
   100  
   101  	return nil
   102  }
   103  

View as plain text