mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 00:47:48 +08:00
102 lines
2.8 KiB
Go
102 lines
2.8 KiB
Go
/*
|
|
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 fs
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/containerd/continuity/devices"
|
|
"github.com/containerd/continuity/sysx"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const (
|
|
// whiteoutPrefix prefix means file is a whiteout. If this is followed
|
|
// by a filename this means that file has been removed from the base
|
|
// layer.
|
|
//
|
|
// See https://github.com/opencontainers/image-spec/blob/master/layer.md#whiteouts
|
|
whiteoutPrefix = ".wh."
|
|
)
|
|
|
|
// overlayFSWhiteoutConvert detects whiteouts and opaque directories.
|
|
//
|
|
// It returns deleted indicator if the file is a character device with 0/0
|
|
// device number. And call changeFn with ChangeKindDelete for opaque
|
|
// directories.
|
|
//
|
|
// Check: https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
|
|
func overlayFSWhiteoutConvert(diffDir, path string, f os.FileInfo, changeFn ChangeFunc) (deleted bool, _ error) {
|
|
if f.Mode()&os.ModeCharDevice != 0 {
|
|
if _, ok := f.Sys().(*syscall.Stat_t); !ok {
|
|
return false, nil
|
|
}
|
|
|
|
maj, min, err := devices.DeviceInfo(f)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return (maj == 0 && min == 0), nil
|
|
}
|
|
|
|
if f.IsDir() {
|
|
originalPath := filepath.Join(diffDir, path)
|
|
opaque, err := getOpaqueValue(originalPath)
|
|
if err != nil {
|
|
if errors.Is(err, unix.ENODATA) {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
if len(opaque) == 1 && opaque[0] == 'y' {
|
|
opaqueDirPath := filepath.Join(path, whiteoutPrefix+".opq")
|
|
return false, changeFn(ChangeKindDelete, opaqueDirPath, nil, nil)
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// getOpaqueValue returns opaque value for a given file.
|
|
func getOpaqueValue(filePath string) ([]byte, error) {
|
|
for _, xattr := range []string{
|
|
"trusted.overlay.opaque",
|
|
// TODO(fuweid):
|
|
//
|
|
// user.overlay.* is available since 5.11. We should check
|
|
// kernel version before read.
|
|
//
|
|
// REF: https://github.com/torvalds/linux/commit/2d2f2d7322ff43e0fe92bf8cccdc0b09449bf2e1
|
|
"user.overlay.opaque",
|
|
} {
|
|
opaque, err := sysx.LGetxattr(filePath, xattr)
|
|
if err != nil {
|
|
if errors.Is(err, unix.ENODATA) || errors.Is(err, unix.ENOTSUP) {
|
|
continue
|
|
}
|
|
return nil, fmt.Errorf("failed to retrieve %s attr: %w", xattr, err)
|
|
}
|
|
return opaque, nil
|
|
}
|
|
return nil, unix.ENODATA
|
|
}
|