go os: permit Rename to read-only file on Windows

rhfm7lfc  于 2个月前  发布在  Go
关注(0)|答案(9)|浏览(29)

在 Windows 10 的 Go 1.13 版本中,重命名只读文件(如 Unix 系统中)是可能的。但在 Go 1.14 版本中,这是不可能的。我没有在发布说明中看到关于这个具体变化的信息,这是有意为之的改变吗?

6bc51xsx

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注解。

mgdq6dx1

mgdq6dx12#

在1.13版本(16f0f9c之前)中,ioutil.WriteFile在Windows上不尊重权限位。因此,即使指定了0444权限,文件始终为0666。这与#26295有关。

bwntbbo3

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.
ljo96ir5

ljo96ir54#

是的,错误出现在WriteFile函数中,而不是Rename函数。呃。

l7mqbcuq

l7mqbcuq5#

啊,很抱歉我的解释太短了。我认为16f0f9c不是回归,而是os.Rename可以像os.Remove一样得到改进。

8yparm6h

8yparm6h6#

https://golang.org/cl/227457提到了这个问题:os: fix Rename for file with read only attribute on Windows

soat7uwm

soat7uwm7#

在Unix系统中,重命名到只读文件是允许的。目录必须可写。

所以问题是,Windows上的os.Rename是否应该努力使这种工作方式相同,通过将文件更改为不可读写。我想我们经常在Windows上尝试这样做,所以对我来说是有意义的,但我对此没有强烈的感觉。
其他意见?
CC @alexbrainman@mattn

iyzzxitl

iyzzxitl8#

我同意iant的观点。

kmb7vmvb

kmb7vmvb9#

其他意见?
这个bug不影响我。但修复会影响我——os.Rename需要做更多工作来实现这个逻辑。我们总是调整Windows代码以匹配任何Unix系统调用的实现。
感谢zx2c4,因为他是16f0f9c的作者。

相关问题