mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-28 20:12:27 +00:00
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>
This commit is contained in:
parent
48e30bb8de
commit
3d0599fca0
@ -95,12 +95,15 @@ type PartialFile struct {
|
|||||||
DeclaredSize int64 // or -1 if unknown
|
DeclaredSize int64 // or -1 if unknown
|
||||||
Received int64 // bytes copied thus far
|
Received int64 // bytes copied thus far
|
||||||
|
|
||||||
// FinalPath is non-empty when the final has been completely
|
// PartialPath is set non-empty in "direct" file mode to the
|
||||||
// written and renamed into place. This is then the complete
|
// in-progress '*.partial' file's path when the peerapi isn't
|
||||||
// path to the file post-rename. This is only set in
|
// being used; see LocalBackend.SetDirectFileRoot.
|
||||||
// "direct" file mode where the peerapi isn't being used; see
|
PartialPath string `json:",omitempty"`
|
||||||
// LocalBackend.SetDirectFileRoot.
|
|
||||||
FinalPath 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
|
// 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 {
|
type incomingFile struct {
|
||||||
name string // "foo.jpg"
|
name string // "foo.jpg"
|
||||||
started time.Time
|
started time.Time
|
||||||
size int64 // or -1 if unknown; never 0
|
size int64 // or -1 if unknown; never 0
|
||||||
w io.Writer // underlying writer
|
w io.Writer // underlying writer
|
||||||
ph *peerAPIHandler
|
ph *peerAPIHandler
|
||||||
|
partialPath string // non-empty in direct mode
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
copied int64
|
copied int64
|
||||||
|
done bool
|
||||||
lastNotify time.Time
|
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.mu.Lock()
|
||||||
f.finalPath = finalPath
|
f.done = true
|
||||||
f.mu.Unlock()
|
f.mu.Unlock()
|
||||||
b := f.ph.ps.b
|
b := f.ph.ps.b
|
||||||
b.sendFileNotify()
|
b.sendFileNotify()
|
||||||
@ -432,7 +433,8 @@ func (f *incomingFile) PartialFile() ipn.PartialFile {
|
|||||||
Started: f.started,
|
Started: f.started,
|
||||||
DeclaredSize: f.size,
|
DeclaredSize: f.size,
|
||||||
Received: f.copied,
|
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,
|
w: f,
|
||||||
ph: h,
|
ph: h,
|
||||||
}
|
}
|
||||||
|
if h.ps.directFileMode {
|
||||||
|
inFile.partialPath = dstFile
|
||||||
|
}
|
||||||
h.ps.b.registerIncomingFile(inFile, true)
|
h.ps.b.registerIncomingFile(inFile, true)
|
||||||
defer h.ps.b.registerIncomingFile(inFile, false)
|
defer h.ps.b.registerIncomingFile(inFile, false)
|
||||||
n, err := io.Copy(inFile, r.Body)
|
n, err := io.Copy(inFile, r.Body)
|
||||||
@ -519,14 +524,8 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if h.ps.directFileMode {
|
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
|
if inFile != nil { // non-zero length; TODO: notify even for zero length
|
||||||
inFile.markAndNotifyDone(finalPath)
|
inFile.markAndNotifyDone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user