
Details about CimFs project are discussed in #8346 Signed-off-by: Amit Barve <ambarve@microsoft.com>
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package cimfs
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/Microsoft/hcsshim/internal/log"
|
|
"github.com/Microsoft/hcsshim/pkg/cimfs/format"
|
|
)
|
|
|
|
var (
|
|
// Equivalent to SDDL of "D:NO_ACCESS_CONTROL".
|
|
nullSd = []byte{1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
)
|
|
|
|
type OpError struct {
|
|
Cim string
|
|
Op string
|
|
Err error
|
|
}
|
|
|
|
func (e *OpError) Error() string {
|
|
s := "cim " + e.Op + " " + e.Cim
|
|
s += ": " + e.Err.Error()
|
|
return s
|
|
}
|
|
|
|
// PathError is the error type returned by most functions in this package.
|
|
type PathError struct {
|
|
Cim string
|
|
Op string
|
|
Path string
|
|
Err error
|
|
}
|
|
|
|
func (e *PathError) Error() string {
|
|
s := "cim " + e.Op + " " + e.Cim
|
|
s += ":" + e.Path
|
|
s += ": " + e.Err.Error()
|
|
return s
|
|
}
|
|
|
|
type LinkError struct {
|
|
Cim string
|
|
Op string
|
|
Old string
|
|
New string
|
|
Err error
|
|
}
|
|
|
|
func (e *LinkError) Error() string {
|
|
return "cim " + e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
|
|
}
|
|
|
|
func validateHeader(h *format.CommonHeader) error {
|
|
if !bytes.Equal(h.Magic[:], format.MagicValue[:]) {
|
|
return fmt.Errorf("not a cim file")
|
|
}
|
|
if h.Version.Major > format.CurrentVersion.Major || h.Version.Major < format.MinSupportedVersion.Major {
|
|
return fmt.Errorf("unsupported cim version. cim version %v must be between %v & %v", h.Version, format.MinSupportedVersion, format.CurrentVersion)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func readFilesystemHeader(f *os.File) (format.FilesystemHeader, error) {
|
|
var fsh format.FilesystemHeader
|
|
|
|
if err := binary.Read(f, binary.LittleEndian, &fsh); err != nil {
|
|
return fsh, fmt.Errorf("reading filesystem header: %w", err)
|
|
}
|
|
|
|
if err := validateHeader(&fsh.Common); err != nil {
|
|
return fsh, fmt.Errorf("validating filesystem header: %w", err)
|
|
}
|
|
return fsh, nil
|
|
}
|
|
|
|
// Returns the paths of all the objectID files associated with the cim at `cimPath`.
|
|
func getObjectIDFilePaths(ctx context.Context, cimPath string) ([]string, error) {
|
|
f, err := os.Open(cimPath)
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("open cim file %s: %w", cimPath, err)
|
|
}
|
|
defer f.Close()
|
|
|
|
fsh, err := readFilesystemHeader(f)
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("readingp cim header: %w", err)
|
|
}
|
|
|
|
paths := []string{}
|
|
for i := 0; i < int(fsh.Regions.Count); i++ {
|
|
path := filepath.Join(filepath.Dir(cimPath), fmt.Sprintf("%s_%v_%d", format.ObjectIDFileName, fsh.Regions.ID, i))
|
|
if _, err := os.Stat(path); err == nil {
|
|
paths = append(paths, path)
|
|
} else {
|
|
log.G(ctx).WithError(err).Warnf("stat for object file %s", path)
|
|
}
|
|
|
|
}
|
|
return paths, nil
|
|
}
|
|
|
|
// Returns the paths of all the region files associated with the cim at `cimPath`.
|
|
func getRegionFilePaths(ctx context.Context, cimPath string) ([]string, error) {
|
|
f, err := os.Open(cimPath)
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("open cim file %s: %w", cimPath, err)
|
|
}
|
|
defer f.Close()
|
|
|
|
fsh, err := readFilesystemHeader(f)
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("reading cim header: %w", err)
|
|
}
|
|
|
|
paths := []string{}
|
|
for i := 0; i < int(fsh.Regions.Count); i++ {
|
|
path := filepath.Join(filepath.Dir(cimPath), fmt.Sprintf("%s_%v_%d", format.RegionFileName, fsh.Regions.ID, i))
|
|
if _, err := os.Stat(path); err == nil {
|
|
paths = append(paths, path)
|
|
} else {
|
|
log.G(ctx).WithError(err).Warnf("stat for region file %s", path)
|
|
}
|
|
}
|
|
return paths, nil
|
|
}
|