pkg/sdk/fsutil/targzfs/file.go (114 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 targzfs
import (
"archive/tar"
"io"
"io/fs"
"time"
)
type tarEntry struct {
h *tar.Header
b []byte
// If the file is a directory, the following property will contain
// owned files.
entries []fs.DirEntry
}
// Implementation of fs.DirEntry for tarEntry.
var _ fs.DirEntry = (*tarEntry)(nil)
// Name returns the basename of the file.
func (f *tarEntry) Name() string {
return f.h.FileInfo().Name()
}
// Type returns file mode.
func (f *tarEntry) Type() fs.FileMode {
return f.h.FileInfo().Mode() & fs.ModeType
}
// IsDir returns whether this file is a directory (always false).
func (f *tarEntry) IsDir() bool {
return f.h.FileInfo().IsDir()
}
// Info returns file info.
func (f *tarEntry) Info() (fs.FileInfo, error) {
return f.h.FileInfo(), nil
}
type tarFile struct {
tarEntry
r io.ReadSeeker
readDirPos int
}
// Implementation of fs.File for tarFile.
var _ fs.File = (*tarFile)(nil)
// Stat returns a fs.FileInfo for the given file.
func (f *tarFile) Stat() (fs.FileInfo, error) {
return f.h.FileInfo(), nil
}
// Read reads the next len(p) bytes from the buffer or until the buffer is drained.
func (f *tarFile) Read(buf []byte) (int, error) {
if f.IsDir() {
return 0, &fs.PathError{Op: "read", Path: f.Name(), Err: fs.ErrInvalid}
}
return f.r.Read(buf)
}
// Close is a no-op.
func (f *tarFile) Close() error {
return nil
}
// Implementation of io.Seeker for tarFile.
var _ io.Seeker = (*tarFile)(nil)
func (f *tarFile) Seek(offset int64, whence int) (int64, error) {
if f.IsDir() {
return 0, &fs.PathError{Op: "seek", Path: f.Name(), Err: fs.ErrInvalid}
}
return f.r.Seek(offset, whence)
}
// Implementation of fs.ReadDirFile for tarFile.
var _ fs.ReadDirFile = (*tarFile)(nil)
func (f *tarFile) ReadDir(n int) ([]fs.DirEntry, error) {
if !f.IsDir() {
return nil, &fs.PathError{Op: "readdir", Path: f.Name(), Err: fs.ErrInvalid}
}
if f.readDirPos >= len(f.entries) {
if n <= 0 {
return nil, nil
}
return nil, io.EOF
}
var entries []fs.DirEntry
if n > 0 && f.readDirPos+n <= len(f.entries) {
entries = f.entries[f.readDirPos : f.readDirPos+n]
f.readDirPos += n
} else {
entries = f.entries[f.readDirPos:]
f.readDirPos += len(entries)
}
return entries, nil
}
// Implmentation of fs.FileInfo for tarFile.
var _ fs.FileInfo = (*tarFile)(nil)
// Size returns the length in bytes for this file.
func (f *tarFile) Size() int64 {
return f.h.Size
}
// Mode returns the mode for this file.
func (f *tarFile) Mode() fs.FileMode {
return f.h.FileInfo().Mode()
}
// Mode returns the mtime for this file (always the Unix epoch).
func (f *tarFile) ModTime() time.Time {
return f.h.ModTime
}
// Sys returns nil.
func (f *tarFile) Sys() interface{} {
return nil
}
// -----------------------------------------------------------------------------
type rootFile struct{}
var _ fs.File = (*rootFile)(nil)
func (rf *rootFile) Stat() (fs.FileInfo, error) {
return rf, nil
}
func (*rootFile) Read([]byte) (int, error) {
return 0, &fs.PathError{Op: "read", Path: ".", Err: fs.ErrInvalid}
}
func (*rootFile) Close() error {
return nil
}
var _ fs.FileInfo = (*rootFile)(nil)
func (rf *rootFile) Name() string {
return "."
}
func (rf *rootFile) Size() int64 {
return 0
}
func (rf *rootFile) Mode() fs.FileMode {
return fs.ModeDir | 0o755
}
func (rf *rootFile) ModTime() time.Time {
return time.Time{}
}
func (rf *rootFile) IsDir() bool {
return true
}
func (rf *rootFile) Sys() interface{} {
return nil
}