...

Source file src/github.com/containerd/continuity/testutil/loopback/loopback_linux.go

Documentation: github.com/containerd/continuity/testutil/loopback

     1  //go:build linux
     2  // +build linux
     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 loopback
    21  
    22  import (
    23  	"bytes"
    24  	"errors"
    25  	"fmt"
    26  	"os"
    27  	"os/exec"
    28  	"strings"
    29  	"syscall"
    30  
    31  	"github.com/sirupsen/logrus"
    32  )
    33  
    34  // New creates a loopback device
    35  func New(size int64) (*Loopback, error) {
    36  	// create temporary file for the disk image
    37  	file, err := os.CreateTemp("", "containerd-test-loopback")
    38  	if err != nil {
    39  		return nil, fmt.Errorf("could not create temporary file for loopback: %w", err)
    40  	}
    41  
    42  	if err := file.Truncate(size); err != nil {
    43  		file.Close()
    44  		os.Remove(file.Name())
    45  		return nil, fmt.Errorf("failed to resize temp file: %w", err)
    46  	}
    47  	file.Close()
    48  
    49  	// create device
    50  	losetup := exec.Command("losetup", "--find", "--show", file.Name())
    51  	var stdout, stderr bytes.Buffer
    52  	losetup.Stdout = &stdout
    53  	losetup.Stderr = &stderr
    54  	if err := losetup.Run(); err != nil {
    55  		os.Remove(file.Name())
    56  		return nil, fmt.Errorf("loopback setup failed (%v): stdout=%q, stderr=%q: %w", losetup.Args, stdout.String(), stderr.String(), err)
    57  	}
    58  
    59  	deviceName := strings.TrimSpace(stdout.String())
    60  	logrus.Debugf("Created loop device %s (using %s)", deviceName, file.Name())
    61  
    62  	cleanup := func() error {
    63  		// detach device
    64  		logrus.Debugf("Removing loop device %s", deviceName)
    65  		losetup := exec.Command("losetup", "--detach", deviceName)
    66  		if out, err := losetup.CombinedOutput(); err != nil {
    67  			return fmt.Errorf("Could not remove loop device %s (%v): %q: %w", deviceName, losetup.Args, string(out), err)
    68  		}
    69  
    70  		// remove file
    71  		logrus.Debugf("Removing temporary file %s", file.Name())
    72  		return os.Remove(file.Name())
    73  	}
    74  
    75  	l := Loopback{
    76  		File:   file.Name(),
    77  		Device: deviceName,
    78  		close:  cleanup,
    79  	}
    80  	return &l, nil
    81  }
    82  
    83  // Loopback device
    84  type Loopback struct {
    85  	// File is the underlying sparse file
    86  	File string
    87  	// Device is /dev/loopX
    88  	Device string
    89  	close  func() error
    90  }
    91  
    92  // SoftSize returns st_size
    93  func (l *Loopback) SoftSize() (int64, error) {
    94  	st, err := os.Stat(l.File)
    95  	if err != nil {
    96  		return 0, err
    97  	}
    98  	return st.Size(), nil
    99  }
   100  
   101  // HardSize returns st_blocks * 512; see stat(2)
   102  func (l *Loopback) HardSize() (int64, error) {
   103  	st, err := os.Stat(l.File)
   104  	if err != nil {
   105  		return 0, err
   106  	}
   107  	st2, ok := st.Sys().(*syscall.Stat_t)
   108  	if !ok {
   109  		return 0, errors.New("st.Sys() is not a *syscall.Stat_t")
   110  	}
   111  	// NOTE: st_blocks has nothing to do with st_blksize; see stat(2)
   112  	return st2.Blocks * 512, nil
   113  }
   114  
   115  // Close detaches the device and removes the underlying file
   116  func (l *Loopback) Close() error {
   117  	return l.close()
   118  }
   119  

View as plain text