mirror of
https://github.com/hanzoai/s3.git
synced 2026-11-03 03:07:41 +00:00
hanzoai/s3 was an AGPL-3.0 MinIO fork whose network-copyleft blocks embedding
and reselling as a managed service. Replace it wholesale with a fork of
SeaweedFS (github.com/seaweedfs/seaweedfs, Apache-2.0, Go) which ships a
built-in S3 gateway + Filer.
- License: AGPL-3.0 -> Apache-2.0 (upstream LICENSE kept verbatim, incl.
"Copyright 2025 Chris Lu"); NOTICE added crediting SeaweedFS. No AGPL/BUSL/
SSPL/GPL or enterprise ("ee") files remain.
- Module: go.mod path set to github.com/hanzoai/s3 with a self-replace
(replace github.com/seaweedfs/seaweedfs => ./) so the ~1800 internal Go files
keep their upstream import paths with zero churn. Internal identifiers and
import paths are intentionally NOT renamed.
- CLI rebrand: the binary is built as `s3` (was `weed`); root usage, per-command
help/usage/flag strings, shell autocomplete program name, and the product name
in CLI output now read "Hanzo S3" / `s3`. Users never see `weed`.
(e.g. `s3 server`, `s3 filer`, `s3 master`, `s3 volume`, `s3 s3`, `s3 mount`.)
- Build: `make` (or `go build -o s3 ./weed`) builds the `s3` binary green;
`cmd/weed-db` and `cmd/weed-sql` also build; `go vet ./weed/command/` clean.
- README/LLM.md rewritten for Hanzo S3; AGENTS.md/CLAUDE.md symlinks preserved.
- Dropped a 33MB prebuilt Mach-O `stress` binary upstream had committed; `.gitignore`
updated to ignore the `s3` build output.
143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
package filer_pb
|
|
|
|
import (
|
|
"google.golang.org/protobuf/encoding/protowire"
|
|
)
|
|
|
|
// ScanMetadataEventSkeleton extracts just the fields the subscription matcher
|
|
// reads, without materializing the entries' chunk lists. ok=false means the
|
|
// caller must fall back to a full unmarshal.
|
|
func ScanMetadataEventSkeleton(data []byte) (skeleton *SubscribeMetadataResponse, ok bool) {
|
|
skeleton = &SubscribeMetadataResponse{}
|
|
rest := data
|
|
for len(rest) > 0 {
|
|
num, typ, n := protowire.ConsumeTag(rest)
|
|
if n < 0 {
|
|
return nil, false
|
|
}
|
|
rest = rest[n:]
|
|
switch {
|
|
case num == 1 && typ == protowire.BytesType: // directory
|
|
v, m := protowire.ConsumeBytes(rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
skeleton.Directory = string(v)
|
|
rest = rest[m:]
|
|
case num == 2 && typ == protowire.BytesType: // event_notification
|
|
if skeleton.EventNotification != nil {
|
|
// repeated occurrences of a message field merge; punt to a full decode
|
|
return nil, false
|
|
}
|
|
v, m := protowire.ConsumeBytes(rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
notification, scanOk := scanEventNotificationSkeleton(v)
|
|
if !scanOk {
|
|
return nil, false
|
|
}
|
|
skeleton.EventNotification = notification
|
|
rest = rest[m:]
|
|
case num == 3 && typ == protowire.VarintType: // ts_ns
|
|
v, m := protowire.ConsumeVarint(rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
skeleton.TsNs = int64(v)
|
|
rest = rest[m:]
|
|
default:
|
|
m := protowire.ConsumeFieldValue(num, typ, rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
rest = rest[m:]
|
|
}
|
|
}
|
|
return skeleton, true
|
|
}
|
|
|
|
func scanEventNotificationSkeleton(data []byte) (*EventNotification, bool) {
|
|
notification := &EventNotification{}
|
|
rest := data
|
|
for len(rest) > 0 {
|
|
num, typ, n := protowire.ConsumeTag(rest)
|
|
if n < 0 {
|
|
return nil, false
|
|
}
|
|
rest = rest[n:]
|
|
switch {
|
|
case num == 1 && typ == protowire.BytesType: // old_entry
|
|
if notification.OldEntry != nil {
|
|
return nil, false
|
|
}
|
|
v, m := protowire.ConsumeBytes(rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
name, scanOk := scanEntryName(v)
|
|
if !scanOk {
|
|
return nil, false
|
|
}
|
|
notification.OldEntry = &Entry{Name: name}
|
|
rest = rest[m:]
|
|
case num == 2 && typ == protowire.BytesType: // new_entry
|
|
if notification.NewEntry != nil {
|
|
return nil, false
|
|
}
|
|
v, m := protowire.ConsumeBytes(rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
name, scanOk := scanEntryName(v)
|
|
if !scanOk {
|
|
return nil, false
|
|
}
|
|
notification.NewEntry = &Entry{Name: name}
|
|
rest = rest[m:]
|
|
case num == 4 && typ == protowire.BytesType: // new_parent_path
|
|
v, m := protowire.ConsumeBytes(rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
notification.NewParentPath = string(v)
|
|
rest = rest[m:]
|
|
default:
|
|
m := protowire.ConsumeFieldValue(num, typ, rest)
|
|
if m < 0 {
|
|
return nil, false
|
|
}
|
|
rest = rest[m:]
|
|
}
|
|
}
|
|
return notification, true
|
|
}
|
|
|
|
// scanEntryName walks the whole entry so field order does not matter.
|
|
func scanEntryName(data []byte) (string, bool) {
|
|
name := ""
|
|
rest := data
|
|
for len(rest) > 0 {
|
|
num, typ, n := protowire.ConsumeTag(rest)
|
|
if n < 0 {
|
|
return "", false
|
|
}
|
|
rest = rest[n:]
|
|
if num == 1 && typ == protowire.BytesType { // name; last occurrence wins like proto merge
|
|
v, m := protowire.ConsumeBytes(rest)
|
|
if m < 0 {
|
|
return "", false
|
|
}
|
|
name = string(v)
|
|
rest = rest[m:]
|
|
continue
|
|
}
|
|
m := protowire.ConsumeFieldValue(num, typ, rest)
|
|
if m < 0 {
|
|
return "", false
|
|
}
|
|
rest = rest[m:]
|
|
}
|
|
return name, true
|
|
}
|