aboutsummaryrefslogtreecommitdiff
path: root/objectstore/loose/write_writer.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-04 12:53:00 +0800
committerGravatar Runxi Yu2026-03-04 12:53:00 +0800
commitb90b167cfbce785088c5236960515bc460e062d8 (patch)
treebcec9ce9f7fe4a63b546c0433002017d05f6a5be /objectstore/loose/write_writer.go
parentrefstore/chain: Split (diff)
signatureNo signature
objectstore/loose: Split
Diffstat (limited to 'objectstore/loose/write_writer.go')
-rw-r--r--objectstore/loose/write_writer.go183
1 files changed, 0 insertions, 183 deletions
diff --git a/objectstore/loose/write_writer.go b/objectstore/loose/write_writer.go
index a0f24f2b..f76c882e 100644
--- a/objectstore/loose/write_writer.go
+++ b/objectstore/loose/write_writer.go
@@ -1,16 +1,11 @@
package loose
import (
- "bytes"
- "crypto/rand"
"errors"
"hash"
- "io/fs"
"os"
- "path/filepath"
"codeberg.org/lindenii/furgit/internal/zlib"
- "codeberg.org/lindenii/furgit/objectheader"
"codeberg.org/lindenii/furgit/objectid"
)
@@ -100,181 +95,3 @@ func (writer *streamWriter) Write(src []byte) (int, error) {
return len(src), nil
}
-
-// Close flushes and closes the underlying zlib stream and temp file.
-// It is safe to call multiple times.
-func (writer *streamWriter) Close() error {
- if writer.closed {
- return nil
- }
-
- writer.closed = true
-
- errZlib := writer.zw.Close()
- errSync := writer.file.Sync()
- errFile := writer.file.Close()
- writer.file = nil
-
- return errors.Join(errZlib, errSync, errFile)
-}
-
-// finalize validates write completeness and atomically publishes the object.
-// Publication is no-clobber: it links tmpRelPath to the object path and treats
-// existing destination objects as success.
-func (writer *streamWriter) finalize() (objectid.ObjectID, error) {
- if writer.finalized {
- return writer.finalID, writer.finalErr
- }
-
- writer.finalized = true
-
- var zero objectid.ObjectID
-
- if !writer.closed {
- err := writer.Close()
- if err != nil {
- writer.finalErr = err
-
- return zero, err
- }
- }
-
- if writer.fullMode && !writer.headerDone {
- writer.finalErr = errors.New("objectstore/loose: missing full object header")
-
- return zero, writer.finalErr
- }
-
- if writer.expectedContentLeft != 0 {
- writer.finalErr = errors.New("objectstore/loose: object content shorter than declared size")
-
- return zero, writer.finalErr
- }
-
- idBytes := writer.hash.Sum(nil)
-
- id, err := objectid.FromBytes(writer.store.algo, idBytes)
- if err != nil {
- writer.finalErr = err
-
- return zero, err
- }
-
- relPath, err := writer.store.objectPath(id)
- if err != nil {
- writer.finalErr = err
-
- return zero, err
- }
-
- dir := filepath.Dir(relPath)
-
- err = writer.store.root.MkdirAll(dir, 0o755)
- if err != nil {
- writer.finalErr = err
-
- return zero, err
- }
-
- cleanup := true
-
- defer func() {
- if cleanup {
- _ = writer.store.root.Remove(writer.tmpRelPath)
- }
- }()
-
- err = writer.store.root.Link(writer.tmpRelPath, relPath)
- if err != nil {
- if errors.Is(err, fs.ErrExist) {
- writer.finalID = id
- cleanup = false
- _ = writer.store.root.Remove(writer.tmpRelPath)
-
- return id, nil
- }
-
- writer.finalErr = err
-
- return zero, err
- }
-
- writer.finalID = id
- cleanup = false
-
- return id, nil
-}
-
-// acceptFull validates and accounts raw full-object input.
-func (writer *streamWriter) acceptFull(src []byte) error {
- if !writer.headerDone {
- nul := bytes.IndexByte(src, 0)
- if nul >= 0 {
- headerChunkLen := nul + 1
- writer.headerBuf = append(writer.headerBuf, src[:headerChunkLen]...)
-
- _, size, _, ok := objectheader.Parse(writer.headerBuf)
- if !ok {
- return errors.New("objectstore/loose: malformed object header")
- }
-
- writer.headerDone = true
- writer.expectedContentLeft = size
-
- return writer.acceptContent(int64(len(src) - headerChunkLen))
- }
-
- writer.headerBuf = append(writer.headerBuf, src...)
-
- return nil
- }
-
- return writer.acceptContent(int64(len(src)))
-}
-
-// acceptContent validates and accounts content byte counts.
-func (writer *streamWriter) acceptContent(n int64) error {
- if n > writer.expectedContentLeft {
- return errors.New("objectstore/loose: object content exceeds declared size")
- }
-
- writer.expectedContentLeft -= n
-
- return nil
-}
-
-// writeRawChunk forwards raw bytes to the hash and deflate pipeline.
-func (writer *streamWriter) writeRawChunk(src []byte) error {
- _, err := writer.hash.Write(src)
- if err != nil {
- return err
- }
-
- _, err = writer.zw.Write(src)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// createTempObjectFile creates a unique temporary object file within dir.
-// The returned path is relative to the objects root.
-func (store *Store) createTempObjectFile(dir string) (string, *os.File, error) {
- for range 16 {
- relPath := filepath.Join(dir, tempObjectFilePrefix+rand.Text())
-
- file, err := store.root.OpenFile(relPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
- if err == nil {
- return relPath, file, nil
- }
-
- if errors.Is(err, fs.ErrExist) {
- continue
- }
-
- return "", nil, err
- }
-
- return "", nil, errors.New("objectstore/loose: failed to create temporary object file")
-}