taildrop: add logic for resuming partial files (#9785)

We add the following API:
* type FileChecksums
* type Checksum
* func Manager.PartialFiles
* func Manager.HashPartialFile
* func ResumeReader

The Manager methods provide the ability to query for partial files
and retrieve a list of checksums for a given partial file.
The ResumeReader function is a helper that wraps an io.Reader
to discard content that is identical locally and remotely.
The FileChecksums type represents the checksums of a file
and is safe to JSON marshal and send over the wire.

Updates tailscale/corp#14772

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
Co-authored-by: Rhea Ghosh <rhea@tailscale.com>
This commit is contained in:
Joe Tsai
2023-10-12 16:50:11 -07:00
committed by GitHub
parent 24f322bc43
commit b1867eb23f
7 changed files with 298 additions and 25 deletions

View File

@@ -45,7 +45,7 @@ func (id ClientID) partialSuffix() string {
// Manager manages the state for receiving and managing taildropped files.
type Manager struct {
Logf logger.Logf
Clock tstime.Clock
Clock tstime.DefaultClock
// Dir is the directory to store received files.
// This main either be the final location for the files
@@ -131,15 +131,15 @@ func validFilenameRune(r rune) bool {
return unicode.IsPrint(r)
}
func (m *Manager) joinDir(baseName string) (fullPath string, ok bool) {
func (m *Manager) joinDir(baseName string) (fullPath string, err error) {
if !utf8.ValidString(baseName) {
return "", false
return "", ErrInvalidFileName
}
if strings.TrimSpace(baseName) != baseName {
return "", false
return "", ErrInvalidFileName
}
if len(baseName) > 255 {
return "", false
return "", ErrInvalidFileName
}
// TODO: validate unicode normalization form too? Varies by platform.
clean := path.Clean(baseName)
@@ -147,17 +147,17 @@ func (m *Manager) joinDir(baseName string) (fullPath string, ok bool) {
clean == "." || clean == ".." ||
strings.HasSuffix(clean, deletedSuffix) ||
strings.HasSuffix(clean, partialSuffix) {
return "", false
return "", ErrInvalidFileName
}
for _, r := range baseName {
if !validFilenameRune(r) {
return "", false
return "", ErrInvalidFileName
}
}
if !filepath.IsLocal(baseName) {
return "", false
return "", ErrInvalidFileName
}
return filepath.Join(m.Dir, baseName), true
return filepath.Join(m.Dir, baseName), nil
}
// IncomingFiles returns a list of active incoming files.