diff options
| author | 2026-02-21 03:46:50 +0800 | |
|---|---|---|
| committer | 2026-02-21 03:46:50 +0800 | |
| commit | 27ee98e7a9a8693db59e755739e10c1c1ba852b4 (patch) | |
| tree | 2b69d6912851d36b06c0a795391120d204605ffe /objectstore/loose/read_reader.go | |
| parent | objectstore: ReadReaderContent should have an advisory declared length (diff) | |
| signature | No signature | |
objectstore/loose: Add loose backend
Diffstat (limited to 'objectstore/loose/read_reader.go')
| -rw-r--r-- | objectstore/loose/read_reader.go | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/objectstore/loose/read_reader.go b/objectstore/loose/read_reader.go new file mode 100644 index 00000000..dde0de07 --- /dev/null +++ b/objectstore/loose/read_reader.go @@ -0,0 +1,84 @@ +package loose + +import ( + "bufio" + "compress/zlib" + "errors" + "io" + "os" + + "codeberg.org/lindenii/furgit/objectid" + "codeberg.org/lindenii/furgit/objecttype" +) + +type objectReader struct { + // reader is the stream exposed by Read. It may be the raw zlib reader + // (full object) or a buffered reader positioned at content bytes only. + reader io.Reader + // file is the underlying loose object file and is closed by Close. + file *os.File + // zr is the zlib decoder and is closed by Close. + zr io.ReadCloser +} + +func (reader *objectReader) Read(dst []byte) (int, error) { + return reader.reader.Read(dst) +} + +func (reader *objectReader) Close() error { + errZlib := reader.zr.Close() + errFile := reader.file.Close() + return errors.Join(errZlib, errFile) +} + +// openInflated opens and zlib-decodes a loose object file. +// The caller owns both returned closers and must close them. +func (store *Store) openInflated(id objectid.ObjectID) (*os.File, io.ReadCloser, error) { + file, err := store.openObject(id) + if err != nil { + return nil, nil, err + } + zr, err := zlib.NewReader(file) + if err != nil { + _ = file.Close() + return nil, nil, err + } + return file, zr, nil +} + +// ReadReaderFull reads a full serialized object stream as "type size\\x00content". +// The caller must close the returned reader. +func (store *Store) ReadReaderFull(id objectid.ObjectID) (io.ReadCloser, error) { + file, zr, err := store.openInflated(id) + if err != nil { + return nil, err + } + return &objectReader{ + reader: zr, + file: file, + zr: zr, + }, nil +} + +// ReadReaderContent reads an object's type, declared content length, and content stream. +// The caller must close the returned reader. +func (store *Store) ReadReaderContent(id objectid.ObjectID) (objecttype.Type, int64, io.ReadCloser, error) { + file, zr, err := store.openInflated(id) + if err != nil { + return objecttype.TypeInvalid, 0, nil, err + } + + br := bufio.NewReader(zr) + ty, size, err := readHeader(br) + if err != nil { + _ = zr.Close() + _ = file.Close() + return objecttype.TypeInvalid, 0, nil, err + } + + return ty, size, &objectReader{ + reader: br, + file: file, + zr: zr, + }, nil +} |
