You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
5.1 KiB
Go
185 lines
5.1 KiB
Go
2 years ago
|
/*
|
||
|
Copyright The containerd Authors.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package fstest
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"io"
|
||
|
"math/rand"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"syscall"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Applier applies single file changes
|
||
|
type Applier interface {
|
||
|
Apply(root string) error
|
||
|
}
|
||
|
|
||
|
type applyFn func(root string) error
|
||
|
|
||
|
func (a applyFn) Apply(root string) error {
|
||
|
return a(root)
|
||
|
}
|
||
|
|
||
|
// CreateFile returns a file applier which creates a file as the
|
||
|
// provided name with the given content and permission.
|
||
|
func CreateFile(name string, content []byte, perm os.FileMode) Applier {
|
||
|
f := func() io.Reader {
|
||
|
return bytes.NewReader(content)
|
||
|
}
|
||
|
return writeFileStream(name, f, perm)
|
||
|
}
|
||
|
|
||
|
// CreateRandomFile returns a file applier which creates a file with random
|
||
|
// content of the given size using the given seed and permission.
|
||
|
func CreateRandomFile(name string, seed, size int64, perm os.FileMode) Applier {
|
||
|
f := func() io.Reader {
|
||
|
return io.LimitReader(rand.New(rand.NewSource(seed)), size)
|
||
|
}
|
||
|
return writeFileStream(name, f, perm)
|
||
|
}
|
||
|
|
||
|
// writeFileStream returns a file applier which creates a file as the
|
||
|
// provided name with the given content from the provided i/o stream and permission.
|
||
|
func writeFileStream(name string, stream func() io.Reader, perm os.FileMode) Applier {
|
||
|
return applyFn(func(root string) (retErr error) {
|
||
|
fullPath := filepath.Join(root, name)
|
||
|
f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer func() {
|
||
|
err := f.Close()
|
||
|
if err != nil && retErr == nil {
|
||
|
retErr = err
|
||
|
}
|
||
|
}()
|
||
|
_, err = io.Copy(f, stream())
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return os.Chmod(fullPath, perm)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Remove returns a file applier which removes the provided file name
|
||
|
func Remove(name string) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Remove(filepath.Join(root, name))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// RemoveAll returns a file applier which removes the provided file name
|
||
|
// as in os.RemoveAll
|
||
|
func RemoveAll(name string) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.RemoveAll(filepath.Join(root, name))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// CreateDir returns a file applier to create the directory with
|
||
|
// the provided name and permission
|
||
|
func CreateDir(name string, perm os.FileMode) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
fullPath := filepath.Join(root, name)
|
||
|
if err := os.MkdirAll(fullPath, perm); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return os.Chmod(fullPath, perm)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Rename returns a file applier which renames a file
|
||
|
func Rename(old, new string) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Rename(filepath.Join(root, old), filepath.Join(root, new))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Chown returns a file applier which changes the ownership of a file
|
||
|
func Chown(name string, uid, gid int) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Chown(filepath.Join(root, name), uid, gid)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Chtimes changes access and mod time of file.
|
||
|
// Use Lchtimes for symbolic links.
|
||
|
func Chtimes(name string, atime, mtime time.Time) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Chtimes(filepath.Join(root, name), atime, mtime)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Chmod returns a file applier which changes the file permission
|
||
|
func Chmod(name string, perm os.FileMode) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Chmod(filepath.Join(root, name), perm)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Symlink returns a file applier which creates a symbolic link
|
||
|
func Symlink(oldname, newname string) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Symlink(oldname, filepath.Join(root, newname))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Link returns a file applier which creates a hard link
|
||
|
func Link(oldname, newname string) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
return os.Link(filepath.Join(root, oldname), filepath.Join(root, newname))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// TODO: Make platform specific, windows applier is always no-op
|
||
|
//func Mknod(name string, mode int32, dev int) Applier {
|
||
|
// return func(root string) error {
|
||
|
// return return syscall.Mknod(path, mode, dev)
|
||
|
// }
|
||
|
//}
|
||
|
|
||
|
func CreateSocket(name string, perm os.FileMode) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
fullPath := filepath.Join(root, name)
|
||
|
fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer syscall.Close(fd)
|
||
|
sa := &syscall.SockaddrUnix{Name: fullPath}
|
||
|
if err := syscall.Bind(fd, sa); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return os.Chmod(fullPath, perm)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Apply returns a new applier from the given appliers
|
||
|
func Apply(appliers ...Applier) Applier {
|
||
|
return applyFn(func(root string) error {
|
||
|
for _, a := range appliers {
|
||
|
if err := a.Apply(root); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
}
|