mirror of
https://github.com/kopia/kopia.git
synced 2026-01-26 23:38:04 -05:00
This was caused by additional resolution of path names only done in UI, which caused \\hostname\share to be treated as relative and resolved against the home directory. Fixes #1385 Fixes #1362
59 lines
1.4 KiB
Go
59 lines
1.4 KiB
Go
// Package atomicfile provides wrappers for atomically writing files in a manner compatible with long filenames.
|
|
package atomicfile
|
|
|
|
import (
|
|
"io"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/natefinch/atomic"
|
|
|
|
"github.com/kopia/kopia/internal/ospath"
|
|
)
|
|
|
|
// Do not prefix files shorter than this, we are intentionally using less than MAX_PATH
|
|
// in Windows to allow some suffixes.
|
|
const maxPathLength = 240
|
|
|
|
// MaybePrefixLongFilenameOnWindows prefixes the given filename with \\?\ on Windows
|
|
// if the filename is longer than 260 characters, which is required to be able to
|
|
// use some low-level Windows APIs.
|
|
// Because long file names have certain limitations:
|
|
// - we must replace forward slashes with backslashes.
|
|
// - dummy path element (\.\) must be removed.
|
|
func MaybePrefixLongFilenameOnWindows(fname string) string {
|
|
if runtime.GOOS != "windows" {
|
|
return fname
|
|
}
|
|
|
|
if len(fname) < maxPathLength {
|
|
return fname
|
|
}
|
|
|
|
fname = strings.TrimPrefix(fname, "\\\\?\\")
|
|
|
|
if !ospath.IsAbs(fname) {
|
|
// only convert absolute paths
|
|
return fname
|
|
}
|
|
|
|
fixed := strings.ReplaceAll(fname, "/", "\\")
|
|
|
|
for {
|
|
fixed2 := strings.ReplaceAll(fixed, "\\.\\", "\\")
|
|
if fixed2 == fixed {
|
|
break
|
|
}
|
|
|
|
fixed = fixed2
|
|
}
|
|
|
|
return "\\\\?\\" + fixed
|
|
}
|
|
|
|
// Write is a wrapper around atomic.WriteFile that handles long file names on Windows.
|
|
func Write(filename string, r io.Reader) error {
|
|
// nolint:wrapcheck
|
|
return atomic.WriteFile(MaybePrefixLongFilenameOnWindows(filename), r)
|
|
}
|