github.com/apptainer/singularity@v3.1.1+incompatible/pkg/ocibundle/tools/overlay.go (about)

     1  // Copyright (c) 2019, 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 tools
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"syscall"
    13  )
    14  
    15  // CreateOverlay creates a writable overlay
    16  func CreateOverlay(bundlePath string) error {
    17  	var err error
    18  
    19  	oldumask := syscall.Umask(0)
    20  	defer syscall.Umask(oldumask)
    21  
    22  	overlayDir := filepath.Join(bundlePath, "overlay")
    23  	if err = os.Mkdir(overlayDir, 0700); err != nil {
    24  		return fmt.Errorf("failed to create %s: %s", overlayDir, err)
    25  	}
    26  	// delete overlay directory in case of error
    27  	defer func() {
    28  		if err != nil {
    29  			os.RemoveAll(overlayDir)
    30  		}
    31  	}()
    32  
    33  	err = syscall.Mount(overlayDir, overlayDir, "", syscall.MS_BIND, "")
    34  	if err != nil {
    35  		return fmt.Errorf("failed to bind %s: %s", overlayDir, err)
    36  	}
    37  	// best effort to cleanup mount
    38  	defer func() {
    39  		if err != nil {
    40  			syscall.Unmount(overlayDir, syscall.MNT_DETACH)
    41  		}
    42  	}()
    43  
    44  	if err = syscall.Mount("", overlayDir, "", syscall.MS_REMOUNT|syscall.MS_BIND, ""); err != nil {
    45  		return fmt.Errorf("failed to remount %s: %s", overlayDir, err)
    46  	}
    47  
    48  	upperDir := filepath.Join(overlayDir, "upper")
    49  	if err = os.Mkdir(upperDir, 0755); err != nil {
    50  		return fmt.Errorf("failed to create %s: %s", upperDir, err)
    51  	}
    52  	workDir := filepath.Join(overlayDir, "work")
    53  	if err = os.Mkdir(workDir, 0700); err != nil {
    54  		return fmt.Errorf("failed to create %s: %s", workDir, err)
    55  	}
    56  	rootFsDir := RootFs(bundlePath).Path()
    57  
    58  	options := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", rootFsDir, upperDir, workDir)
    59  	if err = syscall.Mount("overlay", rootFsDir, "overlay", 0, options); err != nil {
    60  		return fmt.Errorf("failed to mount %s: %s", overlayDir, err)
    61  	}
    62  	return nil
    63  }
    64  
    65  // DeleteOverlay deletes overlay
    66  func DeleteOverlay(bundlePath string) error {
    67  	overlayDir := filepath.Join(bundlePath, "overlay")
    68  	rootFsDir := RootFs(bundlePath).Path()
    69  
    70  	if err := syscall.Unmount(rootFsDir, syscall.MNT_DETACH); err != nil {
    71  		return fmt.Errorf("failed to unmount %s: %s", rootFsDir, err)
    72  	}
    73  	if err := syscall.Unmount(overlayDir, syscall.MNT_DETACH); err != nil {
    74  		return fmt.Errorf("failed to unmount %s: %s", overlayDir, err)
    75  	}
    76  	if err := os.RemoveAll(overlayDir); err != nil {
    77  		return fmt.Errorf("failed to remove %s: %s", overlayDir, err)
    78  	}
    79  	return nil
    80  }