在 Windows 10 的 Go 1.13 版本中,重命名只读文件(如 Unix 系统中)是可能的。但在 Go 1.14 版本中,这是不可能的。我没有在发布说明中看到关于这个具体变化的信息,这是有意为之的改变吗?
6bc51xsx1#
这可能是16f0f9c中的副作用,但我认为这不是回归。在Windows上,os.Chmod和syscall.Chmod根据权限位切换FILE_ATTRIBUTES_READONLY标志。这有点奇怪,但我猜在某个时候做了一些妥协,并选择了这个来Map到一个Unix概念,而Windows并没有以同样的方式真正拥有它。没关系。然而,Chmod中使用的逻辑被遗忘了,从os.Open和syscall.Open中消失了,这后来体现在各种地方,最近的是go模块的只读行为。这使得syscall.Open与syscall.Chmod保持一致,并添加了一个使用ioutil测试权限行为的测试。通过测试我们关心的行为而不是明确测试我们关心的属性位,我们确保在未来不会以意想不到的方式出现回归问题,同时也确保测试在除Windows之外的其他平台上也能正常工作。在这个过程中,我们修复了一些从未起作用过且依赖于错误行为的测试,以及由于错误行为而被禁用的Windows上的测试,并附上了TODO注解。
mgdq6dx12#
在1.13版本(16f0f9c之前)中,ioutil.WriteFile在Windows上不尊重权限位。因此,即使指定了0444权限,文件始终为0666。这与#26295有关。
ioutil.WriteFile
bwntbbo33#
I confirmed below fix this.
diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 96f934d039..581d382f75 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -313,10 +313,29 @@ func Remove(name string) error { func rename(oldname, newname string) error { e := windows.Rename(fixLongPath(oldname), fixLongPath(newname)) - if e != nil { - return &LinkError{"rename", oldname, newname, e} + if e == nil { + return nil } - return nil + + p, e1 := syscall.UTF16PtrFromString(fixLongPath(newname)) + if e1 != nil { + return e1 + } + + a, e1 := syscall.GetFileAttributes(p) + if e1 != nil { + e = e1 + } else { + if a&syscall.FILE_ATTRIBUTE_READONLY != 0 { + if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil { + if e = windows.Rename(fixLongPath(oldname), fixLongPath(newname)); e == nil { + return nil + } + } + } + } + + return &LinkError{"rename", oldname, newname, e} } // Pipe returns a connected pair of Files; reads from r return bytes written to w.
ljo96ir54#
是的,错误出现在WriteFile函数中,而不是Rename函数。呃。
l7mqbcuq5#
啊,很抱歉我的解释太短了。我认为16f0f9c不是回归,而是os.Rename可以像os.Remove一样得到改进。
8yparm6h6#
https://golang.org/cl/227457提到了这个问题:os: fix Rename for file with read only attribute on Windows
os: fix Rename for file with read only attribute on Windows
soat7uwm7#
在Unix系统中,重命名到只读文件是允许的。目录必须可写。
所以问题是,Windows上的os.Rename是否应该努力使这种工作方式相同,通过将文件更改为不可读写。我想我们经常在Windows上尝试这样做,所以对我来说是有意义的,但我对此没有强烈的感觉。其他意见?CC @alexbrainman@mattn
os.Rename
iyzzxitl8#
我同意iant的观点。
kmb7vmvb9#
其他意见?这个bug不影响我。但修复会影响我——os.Rename需要做更多工作来实现这个逻辑。我们总是调整Windows代码以匹配任何Unix系统调用的实现。感谢zx2c4,因为他是16f0f9c的作者。
9条答案
按热度按时间6bc51xsx1#
这可能是16f0f9c中的副作用,但我认为这不是回归。
在Windows上,os.Chmod和syscall.Chmod根据权限位切换FILE_ATTRIBUTES_READONLY标志。这有点奇怪,但我猜在某个时候做了一些妥协,并选择了这个来Map到一个Unix概念,而Windows并没有以同样的方式真正拥有它。没关系。然而,Chmod中使用的逻辑被遗忘了,从os.Open和syscall.Open中消失了,这后来体现在各种地方,最近的是go模块的只读行为。
这使得syscall.Open与syscall.Chmod保持一致,并添加了一个使用ioutil测试权限行为的测试。通过测试我们关心的行为而不是明确测试我们关心的属性位,我们确保在未来不会以意想不到的方式出现回归问题,同时也确保测试在除Windows之外的其他平台上也能正常工作。
在这个过程中,我们修复了一些从未起作用过且依赖于错误行为的测试,以及由于错误行为而被禁用的Windows上的测试,并附上了TODO注解。
mgdq6dx12#
在1.13版本(16f0f9c之前)中,
ioutil.WriteFile
在Windows上不尊重权限位。因此,即使指定了0444权限,文件始终为0666。这与#26295有关。bwntbbo33#
I confirmed below fix this.
ljo96ir54#
是的,错误出现在WriteFile函数中,而不是Rename函数。呃。
l7mqbcuq5#
啊,很抱歉我的解释太短了。我认为16f0f9c不是回归,而是os.Rename可以像os.Remove一样得到改进。
8yparm6h6#
https://golang.org/cl/227457提到了这个问题:
os: fix Rename for file with read only attribute on Windows
soat7uwm7#
在Unix系统中,重命名到只读文件是允许的。目录必须可写。
所以问题是,Windows上的
os.Rename
是否应该努力使这种工作方式相同,通过将文件更改为不可读写。我想我们经常在Windows上尝试这样做,所以对我来说是有意义的,但我对此没有强烈的感觉。其他意见?
CC @alexbrainman@mattn
iyzzxitl8#
我同意iant的观点。
kmb7vmvb9#
其他意见?
这个bug不影响我。但修复会影响我——os.Rename需要做更多工作来实现这个逻辑。我们总是调整Windows代码以匹配任何Unix系统调用的实现。
感谢zx2c4,因为他是16f0f9c的作者。