File: fsutil.go

package info (click to toggle)
singularity-container 4.1.5%2Bds4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 43,876 kB
  • sloc: asm: 14,840; sh: 3,190; ansic: 1,751; awk: 414; makefile: 413; python: 99
file content (146 lines) | stat: -rw-r--r-- 3,180 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package util

import (
	"context"
	"io"
	"os"
	"path/filepath"

	"github.com/containerd/continuity/fs"
	"github.com/moby/buildkit/snapshot"
	"github.com/pkg/errors"
	"github.com/tonistiigi/fsutil"
	fstypes "github.com/tonistiigi/fsutil/types"
)

type ReadRequest struct {
	Filename string
	Range    *FileRange
}

type FileRange struct {
	Offset int
	Length int
}

func withMount(mount snapshot.Mountable, cb func(string) error) error {
	lm := snapshot.LocalMounter(mount)

	root, err := lm.Mount()
	if err != nil {
		return err
	}

	defer func() {
		if lm != nil {
			lm.Unmount()
		}
	}()

	if err := cb(root); err != nil {
		return err
	}

	if err := lm.Unmount(); err != nil {
		return err
	}
	lm = nil
	return nil
}

func ReadFile(ctx context.Context, mount snapshot.Mountable, req ReadRequest) ([]byte, error) {
	var dt []byte

	err := withMount(mount, func(root string) error {
		fp, err := fs.RootPath(root, req.Filename)
		if err != nil {
			return errors.WithStack(err)
		}

		f, err := os.Open(fp)
		if err != nil {
			// The filename here is internal to the mount, so we can restore
			// the request base path for error reporting.
			// See os.DirFS.Open for details.
			if pe, ok := err.(*os.PathError); ok {
				pe.Path = req.Filename
			}
			return errors.WithStack(err)
		}
		defer f.Close()

		var rdr io.Reader = f
		if req.Range != nil {
			rdr = io.NewSectionReader(f, int64(req.Range.Offset), int64(req.Range.Length))
		}
		dt, err = io.ReadAll(rdr)
		if err != nil {
			return errors.WithStack(err)
		}
		return nil
	})
	return dt, err
}

type ReadDirRequest struct {
	Path           string
	IncludePattern string
}

func ReadDir(ctx context.Context, mount snapshot.Mountable, req ReadDirRequest) ([]*fstypes.Stat, error) {
	var (
		rd []*fstypes.Stat
		fo fsutil.FilterOpt
	)
	if req.IncludePattern != "" {
		fo.IncludePatterns = append(fo.IncludePatterns, req.IncludePattern)
	}
	err := withMount(mount, func(root string) error {
		fp, err := fs.RootPath(root, req.Path)
		if err != nil {
			return errors.WithStack(err)
		}
		return fsutil.Walk(ctx, fp, &fo, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return errors.Wrapf(err, "walking %q", root)
			}
			stat, ok := info.Sys().(*fstypes.Stat)
			if !ok {
				// This "can't happen(tm)".
				return errors.Errorf("expected a *fsutil.Stat but got %T", info.Sys())
			}
			rd = append(rd, stat)

			if info.IsDir() {
				return filepath.SkipDir
			}
			return nil
		})
	})
	return rd, err
}

func StatFile(ctx context.Context, mount snapshot.Mountable, path string) (*fstypes.Stat, error) {
	var st *fstypes.Stat
	err := withMount(mount, func(root string) error {
		fp, err := fs.RootPath(root, path)
		if err != nil {
			return errors.WithStack(err)
		}
		if st, err = fsutil.Stat(fp); err != nil {
			// The filename here is internal to the mount, so we can restore
			// the request base path for error reporting.
			// See os.DirFS.Open for details.
			err1 := err
			if err := errors.Cause(err); err != nil {
				err1 = err
			}
			if pe, ok := err1.(*os.PathError); ok {
				pe.Path = path
			}
			return errors.WithStack(err)
		}
		return nil
	})
	return st, err
}