Skip to content

Commit

Permalink
Fix file moving to be safe on Windows.
Browse files Browse the repository at this point in the history
Fix file moving to be safe on Windows. A shim was added
that calls into the Win32 API / MoveFileEx that prevents an error
occurring on windows if the destination already exists. This shim might
not be needed once os.Replace lands, possibly in Go 1.5.

See: golang/go#8914

[#88907658]
  • Loading branch information
David Morhovich, David Varvel and John Shahid authored and mavenraven committed Feb 25, 2015
1 parent 1e59e50 commit 505a1fd
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
2 changes: 1 addition & 1 deletion cached_downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type CachedDownloader interface {
}

func NoopTransform(source, destination string) (int64, error) {
err := os.Rename(source, destination)
err := replace(source, destination)
if err != nil {
return 0, err
}
Expand Down
2 changes: 1 addition & 1 deletion file_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (c *FileCache) Add(cacheKey string, sourcePath string, size int64, cachingI
uniqueName := fmt.Sprintf("%s-%d-%d", cacheKey, time.Now().UnixNano(), c.seq)
cachePath := filepath.Join(c.cachedPath, uniqueName)

err := os.Rename(sourcePath, cachePath)
err := replace(sourcePath, cachePath)
if err != nil {
return nil, err
}
Expand Down
9 changes: 9 additions & 0 deletions replace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// +build !windows

package cacheddownloader

import "os"

func replace(src, dst string) error {
return os.Rename(src, dst)
}
41 changes: 41 additions & 0 deletions replace_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cacheddownloader

import (
"syscall"
"unsafe"
)

func replace(src, dst string) error {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return err
}
defer syscall.FreeLibrary(kernel32)
moveFileExUnicode, err := syscall.GetProcAddress(kernel32, "MoveFileExW")
if err != nil {
return err
}

srcString, err := syscall.UTF16PtrFromString(src)
if err != nil {
return err
}

dstString, err := syscall.UTF16PtrFromString(dst)
if err != nil {
return err
}

srcPtr := uintptr(unsafe.Pointer(srcString))
dstPtr := uintptr(unsafe.Pointer(dstString))

MOVEFILE_REPLACE_EXISTING := 0x1
flag := uintptr(MOVEFILE_REPLACE_EXISTING)

_, _, callErr := syscall.Syscall(uintptr(moveFileExUnicode), 3, srcPtr, dstPtr, flag)
if callErr != 0 {
return callErr
}

return nil
}

0 comments on commit 505a1fd

Please sign in to comment.