Atomic replacement of files on Windows

674 views
Skip to first unread message

Nate Finch

unread,
Oct 10, 2013, 4:09:06 PM10/10/13
to golan...@googlegroups.com
Given two existing files, foo and bar,

os.Rename("foo", "bar") 

will replace bar with the contents of foo on Linux in a single step

On Windows it'll return an error about bar already existing.

Trying to replicate the behavior on Windows (replace bar with foo in a single step).... well, as far as I can tell, you can't do it.  Am I missing something, or is there no actual way to do that in one single step on Windows with the currently implemented syscalls in Go?

On Windows both CopyFileEx and MoveFileEx can be given an overwrite flag, but Go uses MoveFile, which doesn't have that ability.

Yes, I can (and did) write a wrapper around the Windows API MoveFileEx.... I just was surprised there was no way to do this in go as-is.

Should os.Rename overwrite on Windows, like it does on Linux?  It would seem to be more consistent that way.

Kamil Kisiel

unread,
Oct 10, 2013, 4:45:19 PM10/10/13
to golan...@googlegroups.com

On Thursday, October 10, 2013 1:09:06 PM UTC-7, Nate Finch wrote:
Given two existing files, foo and bar,

os.Rename("foo", "bar") 

will replace bar with the contents of foo on Linux in a single step

sometimes.

Ian Lance Taylor

unread,
Oct 10, 2013, 5:02:38 PM10/10/13
to Nate Finch, golang-nuts
It's pretty hard to know what to do with operating system facilities
like this. The Unix rename function provides certain guarantees that
as far as I know are not available on Windows. For example, Unix
guarantees that if bar already exists, at no point during the rename
will any other process be able to see that bar does not exist. If
some program needs that facility, then it would be an error to
implement os.Rename as MoveFileEx, because we would not be providing
what that program expects.

The best we can do for this kind of thing is fall back on what the
platforms provides, and let portable programs pick up the pieces.

If the Windows maintainers want to change syscall.Rename to use
MoveFileEx, that's fine with me. But it is also fine with me if they
want to leave it as is. I don't see any obvious reason to prefer
either possibility.

Ian

brainman

unread,
Oct 10, 2013, 6:18:25 PM10/10/13
to golan...@googlegroups.com
On Friday, 11 October 2013 07:09:06 UTC+11, Nate Finch wrote:

Yes, I can (and did) write a wrapper around the Windows API MoveFileEx.... 

Good man.
 

Should os.Rename overwrite on Windows, like it does on Linux?  It would seem to be more consistent that way.
 
Like Ian said. Using MoveFile, simplest and most commonly used API, sounds like a reasonable compromise.

Alex

Kevin Gillette

unread,
Oct 10, 2013, 7:01:44 PM10/10/13
to golan...@googlegroups.com
Usually, and consistently yea, or consistently nay. There's a reason why rename (the syscall) is prohibited from operating across filesystem boundaries: it's designed to be an atomic, non-copying operation. NFS and friends are the exception, not the rule, and there's no reason why it couldn't be atomic on NFS too -- it may just be local caching and other issues that make it less practical in those situations. If you've got a non-experimental designed-for-unix local filesystem, you can be pretty sure that rename is atomic on that filesystem.
Reply all
Reply to author
Forward
0 new messages