fix(files): 模组包上传也逐段核对 SHA-256、长文件名能写、卡住的导出按时停掉、世界被占用时文件页说明原因并等它结束
This commit is contained in:
59 files changed
+2538
-338
No files matched your search
@@ -79,8 +79,22 @@ var (
|
||||
// ErrNotStaged is an Open with an unknown id, a wrong token, or a spent one.
|
||||
// They are one error on purpose: the internal face answers all three the same.
|
||||
ErrNotStaged = errors.New("fileedit: no such staged upload")
|
||||
// ErrNoDigest is bytes sent without the SHA-256 the client computed over
|
||||
// them, so what arrived cannot be told apart from what was sent.
|
||||
ErrNoDigest = errors.New("fileedit: the upload carries no SHA-256 digest")
|
||||
// ErrDigestMismatch is bytes that do not hash to the digest they were sent
|
||||
// with: they were changed on the way.
|
||||
ErrDigestMismatch = errors.New("fileedit: the bytes that arrived do not match the digest they were sent with")
|
||||
)
|
||||
|
||||
// checkDigest compares the digest of what arrived with the one it was sent with.
|
||||
func checkDigest(got, want []byte) error {
|
||||
if subtle.ConstantTimeCompare(got, want) != 1 {
|
||||
return fmt.Errorf("%w: they hash to %x, sent as %x", ErrDigestMismatch, got, want)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// statfs reports a filesystem's available and total bytes. A var so a test can
|
||||
// stage against a disk of a chosen size.
|
||||
var statfs = func(dir string) (avail, total uint64, err error) {
|
||||
@@ -104,10 +118,17 @@ func (s *Stage) Sweep() error {
|
||||
// it by, plus the func that deletes it. body must end right after size bytes (an
|
||||
// HTTP body with that Content-Length does): Put reads to its end, which is also
|
||||
// what tells the server the body is done.
|
||||
func (s *Stage) Put(body io.Reader, size int64) (Staged, func(), error) {
|
||||
//
|
||||
// want is the SHA-256 the client computed over the bytes it sent (the request's
|
||||
// Content-Digest). Bytes that hash to anything else were changed on the way and
|
||||
// are refused with ErrDigestMismatch; nothing is staged without one.
|
||||
func (s *Stage) Put(body io.Reader, size int64, want []byte) (Staged, func(), error) {
|
||||
if size < 0 {
|
||||
return Staged{}, nil, fmt.Errorf("fileedit: an upload of %d bytes", size)
|
||||
}
|
||||
if len(want) != sha256.Size {
|
||||
return Staged{}, nil, ErrNoDigest
|
||||
}
|
||||
if err := os.MkdirAll(s.Dir, 0o700); err != nil {
|
||||
return Staged{}, nil, fmt.Errorf("fileedit: create the upload stage: %w", err)
|
||||
}
|
||||
@@ -125,7 +146,11 @@ func (s *Stage) Put(body io.Reader, size int64) (Staged, func(), error) {
|
||||
// One byte past size, so the read that finds the end happens here.
|
||||
n, copyErr := io.Copy(io.MultiWriter(f, h), io.LimitReader(src, size+1))
|
||||
closeErr := f.Close()
|
||||
if err := stageFailure(src.err, copyErr, closeErr, n, size); err != nil {
|
||||
err = stageFailure(src.err, copyErr, closeErr, n, size)
|
||||
if err == nil {
|
||||
err = checkDigest(h.Sum(nil), want)
|
||||
}
|
||||
if err != nil {
|
||||
os.Remove(f.Name())
|
||||
return Staged{}, nil, err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user