diff --git a/artifact/image/layerscanning/image/file_node.go b/artifact/image/layerscanning/image/file_node.go index 40740a94..16f5e9a6 100644 --- a/artifact/image/layerscanning/image/file_node.go +++ b/artifact/image/layerscanning/image/file_node.go @@ -94,6 +94,19 @@ func (f *fileNode) ReadAt(b []byte, off int64) (n int, err error) { return f.file.ReadAt(b, off) } +func (f *fileNode) Seek(offset int64, whence int) (n int64, err error) { + if f.isWhiteout { + return 0, fs.ErrNotExist + } + if f.file == nil { + f.file, err = os.Open(f.RealFilePath()) + } + if err != nil { + return 0, err + } + return f.file.Seek(offset, whence) +} + // Close closes the real file referred to by the fileNode and resets the file field. func (f *fileNode) Close() error { if f.file != nil { diff --git a/artifact/image/layerscanning/image/file_node_test.go b/artifact/image/layerscanning/image/file_node_test.go index d5b39dad..0d4c5ca7 100644 --- a/artifact/image/layerscanning/image/file_node_test.go +++ b/artifact/image/layerscanning/image/file_node_test.go @@ -400,6 +400,78 @@ func TestReadAt(t *testing.T) { } } +// Test for the Seek method +func TestSeek(t *testing.T) { + tempDir := t.TempDir() + os.WriteFile(path.Join(tempDir, "bar"), []byte("bar"), 0600) + + // Test seeking to different positions + tests := []struct { + name string + offset int64 + whence int + want int64 + }{ + { + name: "seek to beginning", + offset: 0, + whence: io.SeekStart, + want: 0, + }, + { + name: "seek to current position", + offset: 0, + whence: io.SeekCurrent, + want: 0, + }, + { + name: "seek to end", + offset: 0, + whence: io.SeekEnd, + want: 3, + }, + { + name: "seek to 10 bytes from beginning", + offset: 10, + whence: io.SeekStart, + want: 10, + }, + { + name: "seek to 10 bytes from current position (at 0)", + offset: 10, + whence: io.SeekCurrent, + want: 10, + }, + { + name: "seek to 2 bytes from end", + offset: -2, + whence: io.SeekEnd, + want: 1, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Create a fileNode for the opened file + fileNode := &fileNode{ + extractDir: tempDir, + originLayerID: "", + virtualPath: "/bar", + isWhiteout: false, + mode: filePermission, + } + gotPos, err := fileNode.Seek(tc.offset, tc.whence) + fileNode.Close() + if err != nil { + t.Fatalf("Seek failed: %v", err) + } + if gotPos != tc.want { + t.Errorf("Seek returned incorrect position: got %d, want %d", gotPos, tc.want) + } + }) + } +} + func TestClose(t *testing.T) { tempDir := t.TempDir() os.WriteFile(path.Join(tempDir, "bar"), []byte("bar"), 0600)