package archive import ( "context" "fmt" "io" "git.kmsign.ru/royalcat/tstor/pkg/ioutils" "git.kmsign.ru/royalcat/tstor/src/vfs" "github.com/nwaples/rardecode/v2" "github.com/royalcat/ctxio" ) var _ archiveLoader = RarLoader func RarLoader(ctx context.Context, archivePath string, f vfs.File, size int64) (map[string]fileEntry, error) { hash, err := vfs.FileHash(ctx, f) if err != nil { return nil, err } reader := ioutils.WrapIoReadSeeker(ctx, f, size) r, err := rardecode.NewReader(reader) if err != nil { return nil, err } out := make(map[string]fileEntry) for { header, err := r.Next() if err == io.EOF { break } if err != nil { return nil, err } name := header.Name af := func(ctx context.Context) (ctxio.ReadCloser, error) { reader := ioutils.WrapIoReadSeeker(ctx, f, size) r, err := rardecode.NewReader(reader) if err != nil { return nil, err } for header, err := r.Next(); err != io.EOF; header, err = r.Next() { if err != nil { return nil, err } if header.Name == name { return ctxio.NopCloser(ctxio.WrapIoReader(r)), nil } } return nil, fmt.Errorf("file with name '%s' not found", name) } rr := newRandomReaderFromLinear(archiveFileIndex{archiveHash: hash, filename: header.Name}, header.UnPackedSize, af) out[vfs.AbsPath(header.Name)] = fileEntry{ FileInfo: vfs.NewFileInfo(header.Name, header.UnPackedSize, header.ModificationTime), open: func(ctx context.Context) (vfs.File, error) { return newArchiveFile(header.Name, header.UnPackedSize, rr), nil }, } } return out, nil }