...

Source file src/gitlab.com/tslocum/preallocate/preallocate.go

Documentation: gitlab.com/tslocum/preallocate

     1  // Package preallocate allocates disk space efficiently via syscall (on
     2  // supported platforms and filesystems) or by writing null bytes.
     3  //
     4  // Files opened with O_APPEND are not supported.
     5  package preallocate
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"os"
    12  
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // NullBufferSize determines the maximum size of NULL byte blocks written to
    17  // files when falling back to WriteSeeker.
    18  const NullBufferSize = 512 * 1024 // 512 KiB
    19  
    20  // File preallocates a file via syscall (when supported) or WriteSeeker.
    21  func File(file *os.File, size int64) error {
    22  	if size < 0 {
    23  		return errors.New("invalid preallocation size")
    24  	} else if size == 0 {
    25  		return nil
    26  	}
    27  
    28  	return preallocFile(file, size)
    29  }
    30  
    31  // TempFile preallocates a temporary file (see File and ioutil.TempFile).
    32  func TempFile(dir string, pattern string, size int64) (*os.File, error) {
    33  	if size < 0 {
    34  		return nil, errors.New("invalid preallocation size")
    35  	}
    36  
    37  	tempFile, err := ioutil.TempFile(dir, pattern)
    38  	if err != nil {
    39  		return nil, errors.Wrap(err, "failed to create temporary file")
    40  	}
    41  
    42  	return tempFile, File(tempFile, size)
    43  }
    44  
    45  // WriteSeeker preallocates an io.WriteSeeker by writing null bytes.
    46  func WriteSeeker(w io.WriteSeeker, size int64) error {
    47  	if size < 0 {
    48  		return errors.New("invalid preallocation size")
    49  	}
    50  
    51  	var (
    52  		b         []byte
    53  		remaining = size
    54  		wrote     int
    55  		err       error
    56  	)
    57  
    58  	_, err = w.Seek(0, 0)
    59  	if err != nil {
    60  		return err
    61  	}
    62  
    63  	if remaining > NullBufferSize {
    64  		b = make([]byte, NullBufferSize)
    65  		for {
    66  			wrote, err = w.Write(b)
    67  			if err != nil {
    68  				return err
    69  			} else if int64(wrote) != NullBufferSize {
    70  				return fmt.Errorf("failed to preallocate file: write operation interrupted at %d/%d bytes", wrote, NullBufferSize)
    71  			}
    72  
    73  			remaining -= NullBufferSize
    74  			if remaining < NullBufferSize {
    75  				break
    76  			}
    77  		}
    78  	}
    79  
    80  	if remaining > 0 {
    81  		if b != nil {
    82  			b = b[0:remaining]
    83  		} else {
    84  			b = make([]byte, remaining)
    85  		}
    86  
    87  		wrote, err = w.Write(b)
    88  		if err != nil {
    89  			return err
    90  		} else if int64(wrote) != remaining {
    91  			return fmt.Errorf("failed to preallocate file: write operation interrupted at %d/%d bytes", wrote, remaining)
    92  		}
    93  	}
    94  
    95  	_, err = w.Seek(0, 0)
    96  	return err
    97  }
    98  

View as plain text