-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathwriter.go
More file actions
86 lines (75 loc) · 1.64 KB
/
Copy pathwriter.go
File metadata and controls
86 lines (75 loc) · 1.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package pgfs
import (
"hash"
"io/fs"
"log/slog"
"math"
"net/http"
"github.com/google/uuid"
)
// writer writes data in a large object,
// and inserts a row in the metadata table
// when closed.
type writer struct {
fd int32
oid OID
id uuid.UUID
sys Sys
contentType string
size int64
hasher hash.Hash
fsys *FS
closed bool
tag []byte // holds the first 512 bytes
}
// Write implements [io.WriteCloser].
func (w *writer) Write(b []byte) (n int, err error) {
if w.closed {
err = fs.ErrClosed
return
}
n, err = write(w.fsys.conn, w.fd, b)
w.size += int64(n)
w.hasher.Write(b[:n])
// Store up to 512b for [http.DetectContentType].
if w.contentType == "" {
if m := 512 - len(w.tag); n > 0 && m > 0 {
i := int(math.Min(float64(n), float64(m)))
w.tag = append(w.tag, b[:i]...)
}
}
return
}
// Close implements [io.WriteCloser].
func (w *writer) Close() error {
if w.closed {
return nil
}
defer func() {
if err := close(w.fsys.conn, w.fd); err != nil {
slog.Error("error closing lo", "id", w.id, "err", err)
}
w.closed = true
}()
if w.contentType == "" {
w.contentType = http.DetectContentType(w.tag)
}
const q = `
INSERT INTO pgfs_metadata (
oid, id, sys,
content_size, content_type, content_sha256
)
VALUES (
$1, $2, $3,
$4, $5, $6
)
`
_, err := w.fsys.conn.Exec(q, w.oid, w.id, w.sys, w.size, w.contentType, w.hasher.Sum(nil))
if err != nil {
if uerr := unlink(w.fsys.conn, w.oid); uerr != nil {
slog.Error("error unlinking lo after insert error", "id", w.id, "oid", w.oid, "err", uerr)
}
return err
}
return nil
}