Refuse a path listed twice in a manifest (closes #170)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
gen given arguments whose files share a path, such as gen a b with a.txt in both, or gen . ., now fails while listing the files, before hashing any, naming the path and both files. Builder.AddFile and Builder.AddFileWithHash refuse a path already added. Loading refuses a manifest that lists a path twice, compared byte for byte; fetch keeps its own letter-case check. The Path Rules in docs/FORMAT.md say each path appears at most once. The decode-size test listed one path 1000 times; each entry now has its own path of the same length. Model: opus-5-5
This commit was merged in pull request #174.
This commit is contained in:
+25
-12
@@ -38,6 +38,7 @@ var (
|
||||
errNegativeSize = errors.New("size cannot be negative")
|
||||
errHashNotMultihash = errors.New("hash is not a valid multihash")
|
||||
errHashTooShort = errors.New("hash digest is too short")
|
||||
errDuplicatePath = errors.New("duplicate path")
|
||||
)
|
||||
|
||||
// ValidatePath checks that a file path conforms to manifest path invariants:
|
||||
@@ -115,6 +116,7 @@ type FileHashProgress struct {
|
||||
type Builder struct {
|
||||
mu sync.Mutex
|
||||
files []*MFFilePath
|
||||
paths map[string]bool // the path of each entry in files
|
||||
createdAt time.Time
|
||||
includeTimestamps bool
|
||||
signingOptions *SigningOptions
|
||||
@@ -125,6 +127,7 @@ type Builder struct {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
files: make([]*MFFilePath, 0),
|
||||
paths: make(map[string]bool),
|
||||
createdAt: time.Now(),
|
||||
}
|
||||
}
|
||||
@@ -138,6 +141,7 @@ func (b *Builder) SetSeed(seed string) {
|
||||
}
|
||||
|
||||
// AddFile reads file content from reader, computes hashes, and adds to manifest.
|
||||
// A path already added is refused once the file is read.
|
||||
// Only mode's permission bits (mode.Perm()) are recorded; 0 records none.
|
||||
// Progress updates are sent to the progress channel (if non-nil) without blocking.
|
||||
// Returns the number of bytes read.
|
||||
@@ -204,11 +208,7 @@ func (b *Builder) AddFile(
|
||||
Mode: uint32(mode.Perm()),
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
b.files = append(b.files, entry)
|
||||
b.mu.Unlock()
|
||||
|
||||
return totalRead, nil
|
||||
return totalRead, b.addEntry(entry)
|
||||
}
|
||||
|
||||
// sendFileHashProgress sends a progress update without blocking.
|
||||
@@ -234,8 +234,9 @@ func (b *Builder) FileCount() int {
|
||||
// AddFileWithHash adds a file entry with a pre-computed hash.
|
||||
// This is useful when the hash is already known (e.g., from an existing manifest).
|
||||
// Only mode's permission bits (mode.Perm()) are recorded; 0 records none.
|
||||
// Returns an error if path is invalid, size is negative, or hash is not a
|
||||
// multihash with a digest of at least 32 bytes, as long as SHA-256's.
|
||||
// Returns an error if path is invalid or already added, size is negative,
|
||||
// or hash is not a multihash with a digest of at least 32 bytes, as long
|
||||
// as SHA-256's.
|
||||
func (b *Builder) AddFileWithHash(
|
||||
path RelFilePath,
|
||||
size FileSize,
|
||||
@@ -277,11 +278,7 @@ func (b *Builder) AddFileWithHash(
|
||||
Mode: uint32(mode.Perm()),
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
b.files = append(b.files, entry)
|
||||
b.mu.Unlock()
|
||||
|
||||
return nil
|
||||
return b.addEntry(entry)
|
||||
}
|
||||
|
||||
// SetIncludeTimestamps controls whether the manifest includes a createdAt timestamp.
|
||||
@@ -349,3 +346,19 @@ func (b *Builder) Build(ctx context.Context, w io.Writer) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addEntry adds entry to the manifest unless an entry with its path is
|
||||
// already there.
|
||||
func (b *Builder) addEntry(entry *MFFilePath) error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if b.paths[entry.GetPath()] {
|
||||
return fmt.Errorf("%w %q", errDuplicatePath, entry.GetPath())
|
||||
}
|
||||
|
||||
b.paths[entry.GetPath()] = true
|
||||
b.files = append(b.files, entry)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user