github.com/apptainer/singularity@v3.1.1+incompatible/internal/pkg/util/fs/helper.go (about)

     1  // Copyright (c) 2018, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package fs
     7  
     8  import (
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"syscall"
    13  )
    14  
    15  // IsFile check if name component is regular file
    16  func IsFile(name string) bool {
    17  	info, err := os.Stat(name)
    18  	if err != nil {
    19  		return false
    20  	}
    21  	return info.Mode().IsRegular()
    22  }
    23  
    24  // IsDir check if name component is a directory
    25  func IsDir(name string) bool {
    26  	info, err := os.Stat(name)
    27  	if err != nil {
    28  		return false
    29  	}
    30  	return info.Mode().IsDir()
    31  }
    32  
    33  // IsLink check if name component is a symlink
    34  func IsLink(name string) bool {
    35  	info, err := os.Lstat(name)
    36  	if err != nil {
    37  		return false
    38  	}
    39  	return (info.Mode()&os.ModeSymlink != 0)
    40  }
    41  
    42  // IsOwner check if name component is owned by user identified with uid
    43  func IsOwner(name string, uid uint32) bool {
    44  	info, err := os.Stat(name)
    45  	if err != nil {
    46  		return false
    47  	}
    48  	return (info.Sys().(*syscall.Stat_t).Uid == uid)
    49  }
    50  
    51  // IsExec check if name component has executable bit permission set
    52  func IsExec(name string) bool {
    53  	info, err := os.Stat(name)
    54  	if err != nil {
    55  		return false
    56  	}
    57  	return (info.Sys().(*syscall.Stat_t).Mode&syscall.S_IXUSR != 0)
    58  }
    59  
    60  // IsSuid check if name component has setuid bit permission set
    61  func IsSuid(name string) bool {
    62  	info, err := os.Stat(name)
    63  	if err != nil {
    64  		return false
    65  	}
    66  	return (info.Sys().(*syscall.Stat_t).Mode&syscall.S_ISUID != 0)
    67  }
    68  
    69  // MkdirAll creates a directory and parents if it doesn't exist with
    70  // mode after umask reset
    71  func MkdirAll(path string, mode os.FileMode) error {
    72  	oldmask := syscall.Umask(0)
    73  	defer syscall.Umask(oldmask)
    74  
    75  	return os.MkdirAll(path, mode)
    76  }
    77  
    78  // Mkdir creates a directory if it doesn't exist with
    79  // mode after umask reset
    80  func Mkdir(path string, mode os.FileMode) error {
    81  	oldmask := syscall.Umask(0)
    82  	defer syscall.Umask(oldmask)
    83  
    84  	return os.Mkdir(path, mode)
    85  }
    86  
    87  // RootDir returns the root directory of path (rootdir of /my/path is /my).
    88  // Returns "." if path is empty
    89  func RootDir(path string) string {
    90  	if path == "" {
    91  		return "."
    92  	}
    93  
    94  	p := filepath.Clean(path)
    95  	iter := filepath.Dir(p)
    96  	for iter != "/" && iter != "." {
    97  		p = iter
    98  		iter = filepath.Dir(p)
    99  	}
   100  
   101  	return p
   102  }
   103  
   104  // EvalRelative evaluates symlinks in path relative to root path. This
   105  // function doesn't return error but always returns an evaluated path
   106  func EvalRelative(path string, root string) string {
   107  	splitted := strings.Split(filepath.Clean(path), string(os.PathSeparator))
   108  	dest := string(os.PathSeparator)
   109  
   110  	for i := 1; i < len(splitted); i++ {
   111  		s := splitted[i : i+1][0]
   112  		dest = filepath.Join(dest, s)
   113  
   114  		if s != "" {
   115  			rootDestPath := filepath.Join(root, dest)
   116  			for {
   117  				target, err := filepath.EvalSymlinks(rootDestPath)
   118  				if err != nil {
   119  					break
   120  				}
   121  				if !strings.HasPrefix(target, root) {
   122  					rootDestPath = filepath.Join(root, target)
   123  					continue
   124  				}
   125  				dest = strings.Replace(target, root, "", 1)
   126  				break
   127  			}
   128  		}
   129  	}
   130  
   131  	return dest
   132  }
   133  
   134  // Touch behaves like touch command.
   135  func Touch(path string) error {
   136  	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	f.Close()
   141  	return nil
   142  }