...

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

Documentation: github.com/containerd/continuity/fs/fstest

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package fstest
    18  
    19  import (
    20  	"bytes"
    21  	"io"
    22  	"math/rand"
    23  	"os"
    24  	"path/filepath"
    25  	"syscall"
    26  	"time"
    27  )
    28  
    29  // Applier applies single file changes
    30  type Applier interface {
    31  	Apply(root string) error
    32  }
    33  
    34  type applyFn func(root string) error
    35  
    36  func (a applyFn) Apply(root string) error {
    37  	return a(root)
    38  }
    39  
    40  // CreateFile returns a file applier which creates a file as the
    41  // provided name with the given content and permission.
    42  func CreateFile(name string, content []byte, perm os.FileMode) Applier {
    43  	f := func() io.Reader {
    44  		return bytes.NewReader(content)
    45  	}
    46  	return writeFileStream(name, f, perm)
    47  }
    48  
    49  // CreateRandomFile returns a file applier which creates a file with random
    50  // content of the given size using the given seed and permission.
    51  func CreateRandomFile(name string, seed, size int64, perm os.FileMode) Applier {
    52  	f := func() io.Reader {
    53  		return io.LimitReader(rand.New(rand.NewSource(seed)), size)
    54  	}
    55  	return writeFileStream(name, f, perm)
    56  }
    57  
    58  // writeFileStream returns a file applier which creates a file as the
    59  // provided name with the given content from the provided i/o stream and permission.
    60  func writeFileStream(name string, stream func() io.Reader, perm os.FileMode) Applier {
    61  	return applyFn(func(root string) (retErr error) {
    62  		fullPath := filepath.Join(root, name)
    63  		f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
    64  		if err != nil {
    65  			return err
    66  		}
    67  		defer func() {
    68  			err := f.Sync()
    69  			if err != nil && retErr == nil {
    70  				retErr = err
    71  			}
    72  
    73  			err = f.Close()
    74  			if err != nil && retErr == nil {
    75  				retErr = err
    76  			}
    77  		}()
    78  		_, err = io.Copy(f, stream())
    79  		if err != nil {
    80  			return err
    81  		}
    82  		return os.Chmod(fullPath, perm)
    83  	})
    84  }
    85  
    86  // Remove returns a file applier which removes the provided file name
    87  func Remove(name string) Applier {
    88  	return applyFn(func(root string) error {
    89  		return os.Remove(filepath.Join(root, name))
    90  	})
    91  }
    92  
    93  // RemoveAll returns a file applier which removes the provided file name
    94  // as in os.RemoveAll
    95  func RemoveAll(name string) Applier {
    96  	return applyFn(func(root string) error {
    97  		return os.RemoveAll(filepath.Join(root, name))
    98  	})
    99  }
   100  
   101  // CreateDir returns a file applier to create the directory with
   102  // the provided name and permission
   103  func CreateDir(name string, perm os.FileMode) Applier {
   104  	return applyFn(func(root string) error {
   105  		fullPath := filepath.Join(root, name)
   106  		if err := os.MkdirAll(fullPath, perm); err != nil {
   107  			return err
   108  		}
   109  		return os.Chmod(fullPath, perm)
   110  	})
   111  }
   112  
   113  // Rename returns a file applier which renames a file
   114  func Rename(old, new string) Applier {
   115  	return applyFn(func(root string) error {
   116  		return os.Rename(filepath.Join(root, old), filepath.Join(root, new))
   117  	})
   118  }
   119  
   120  // Chown returns a file applier which changes the ownership of a file
   121  func Chown(name string, uid, gid int) Applier {
   122  	return applyFn(func(root string) error {
   123  		return os.Chown(filepath.Join(root, name), uid, gid)
   124  	})
   125  }
   126  
   127  // Chtimes changes access and mod time of file.
   128  // Use Lchtimes for symbolic links.
   129  func Chtimes(name string, atime, mtime time.Time) Applier {
   130  	return applyFn(func(root string) error {
   131  		return os.Chtimes(filepath.Join(root, name), atime, mtime)
   132  	})
   133  }
   134  
   135  // Chmod returns a file applier which changes the file permission
   136  func Chmod(name string, perm os.FileMode) Applier {
   137  	return applyFn(func(root string) error {
   138  		return os.Chmod(filepath.Join(root, name), perm)
   139  	})
   140  }
   141  
   142  // Symlink returns a file applier which creates a symbolic link
   143  func Symlink(oldname, newname string) Applier {
   144  	return applyFn(func(root string) error {
   145  		return os.Symlink(oldname, filepath.Join(root, newname))
   146  	})
   147  }
   148  
   149  // Link returns a file applier which creates a hard link
   150  func Link(oldname, newname string) Applier {
   151  	return applyFn(func(root string) error {
   152  		return os.Link(filepath.Join(root, oldname), filepath.Join(root, newname))
   153  	})
   154  }
   155  
   156  // TODO: Make platform specific, windows applier is always no-op
   157  //func Mknod(name string, mode int32, dev int) Applier {
   158  //	return func(root string) error {
   159  //		return return syscall.Mknod(path, mode, dev)
   160  //	}
   161  //}
   162  
   163  func CreateSocket(name string, perm os.FileMode) Applier {
   164  	return applyFn(func(root string) error {
   165  		fullPath := filepath.Join(root, name)
   166  		fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
   167  		if err != nil {
   168  			return err
   169  		}
   170  		defer syscall.Close(fd)
   171  		sa := &syscall.SockaddrUnix{Name: fullPath}
   172  		if err := syscall.Bind(fd, sa); err != nil {
   173  			return err
   174  		}
   175  		return os.Chmod(fullPath, perm)
   176  	})
   177  }
   178  
   179  // Apply returns a new applier from the given appliers
   180  func Apply(appliers ...Applier) Applier {
   181  	return applyFn(func(root string) error {
   182  		for _, a := range appliers {
   183  			if err := a.Apply(root); err != nil {
   184  				return err
   185  			}
   186  		}
   187  		return nil
   188  	})
   189  }
   190  

View as plain text