ipn{,/ipnlocal}: in direct file receive mode, don't rename partial file
Let caller (macOS) do it so Finder progress bar can be dismissed without races. Updates tailscale/corp#1575 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>pull/1749/head
parent
48e30bb8de
commit
3d0599fca0
|
@ -95,12 +95,15 @@ type PartialFile struct {
|
|||
DeclaredSize int64 // or -1 if unknown
|
||||
Received int64 // bytes copied thus far
|
||||
|
||||
// FinalPath is non-empty when the final has been completely
|
||||
// written and renamed into place. This is then the complete
|
||||
// path to the file post-rename. This is only set in
|
||||
// "direct" file mode where the peerapi isn't being used; see
|
||||
// LocalBackend.SetDirectFileRoot.
|
||||
FinalPath string `json:",omitempty"`
|
||||
// PartialPath is set non-empty in "direct" file mode to the
|
||||
// in-progress '*.partial' file's path when the peerapi isn't
|
||||
// being used; see LocalBackend.SetDirectFileRoot.
|
||||
PartialPath string `json:",omitempty"`
|
||||
|
||||
// Done is set in "direct" mode when the partial file has been
|
||||
// closed and is ready for the caller to rename away the
|
||||
// ".partial" suffix.
|
||||
Done bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
// StateKey is an opaque identifier for a set of LocalBackend state
|
||||
|
|
|
@ -381,21 +381,22 @@ This is my Tailscale device. Your device is %v.
|
|||
}
|
||||
|
||||
type incomingFile struct {
|
||||
name string // "foo.jpg"
|
||||
started time.Time
|
||||
size int64 // or -1 if unknown; never 0
|
||||
w io.Writer // underlying writer
|
||||
ph *peerAPIHandler
|
||||
name string // "foo.jpg"
|
||||
started time.Time
|
||||
size int64 // or -1 if unknown; never 0
|
||||
w io.Writer // underlying writer
|
||||
ph *peerAPIHandler
|
||||
partialPath string // non-empty in direct mode
|
||||
|
||||
mu sync.Mutex
|
||||
copied int64
|
||||
done bool
|
||||
lastNotify time.Time
|
||||
finalPath string // non-empty in direct mode, when file is done
|
||||
}
|
||||
|
||||
func (f *incomingFile) markAndNotifyDone(finalPath string) {
|
||||
func (f *incomingFile) markAndNotifyDone() {
|
||||
f.mu.Lock()
|
||||
f.finalPath = finalPath
|
||||
f.done = true
|
||||
f.mu.Unlock()
|
||||
b := f.ph.ps.b
|
||||
b.sendFileNotify()
|
||||
|
@ -432,7 +433,8 @@ func (f *incomingFile) PartialFile() ipn.PartialFile {
|
|||
Started: f.started,
|
||||
DeclaredSize: f.size,
|
||||
Received: f.copied,
|
||||
FinalPath: f.finalPath,
|
||||
PartialPath: f.partialPath,
|
||||
Done: f.done,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,6 +504,9 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
|||
w: f,
|
||||
ph: h,
|
||||
}
|
||||
if h.ps.directFileMode {
|
||||
inFile.partialPath = dstFile
|
||||
}
|
||||
h.ps.b.registerIncomingFile(inFile, true)
|
||||
defer h.ps.b.registerIncomingFile(inFile, false)
|
||||
n, err := io.Copy(inFile, r.Body)
|
||||
|
@ -519,14 +524,8 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
if h.ps.directFileMode {
|
||||
finalPath := strings.TrimSuffix(dstFile, partialSuffix)
|
||||
if err := os.Rename(dstFile, finalPath); err != nil {
|
||||
h.logf("Rename error: %v", err)
|
||||
http.Error(w, "error renaming file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if inFile != nil { // non-zero length; TODO: notify even for zero length
|
||||
inFile.markAndNotifyDone(finalPath)
|
||||
inFile.markAndNotifyDone()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue